Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212/* * Fast486 386/486 CPU Emulation Library * extraops.c * * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* INCLUDES *******************************************************************/
#include <windef.h>
// #define NDEBUG#include <debug.h>
#include <fast486.h>#include "opcodes.h"#include "common.h"#include "opgroups.h"#include "extraops.h"
/* PUBLIC VARIABLES ***********************************************************/
FAST486_OPCODE_HANDLER_PROCFast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] ={ Fast486ExtOpcodeGroup0F00, /* 0x00 - 0x01 */ Fast486ExtOpcodeGroup0F01, Fast486ExtOpcodeLar, /* 0x02 */ Fast486ExtOpcodeLsl, /* 0x03 */ Fast486ExtOpcodeInvalid, /* 0x04 - 0x05 */ // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeClts, /* 0x06 */ Fast486ExtOpcodeInvalid, /* 0x07 */ // Invalid Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x08 NOT IMPLEMENTED Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x09 NOT IMPLEMENTED Fast486ExtOpcodeInvalid, /* 0x0A */ // Invalid Fast486ExtOpcode0F0B, /* 0x0B */ // Reserved (UD2) Fast486ExtOpcodeInvalid, /* 0x0C - 0x1F */ // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeStoreControlReg, /* 0x20 */ Fast486ExtOpcodeStoreDebugReg, /* 0x21 */ Fast486ExtOpcodeLoadControlReg, /* 0x22 */ Fast486ExtOpcodeLoadDebugReg, /* 0x23 */ Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x24 NOT IMPLEMENTED Fast486ExtOpcodeInvalid, /* 0x25 */ // Invalid Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x26 NOT IMPLEMENTED Fast486ExtOpcodeInvalid, /* 0x27 - 0x7F */ // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeConditionalJmp, /* 0x80 - 0x8F */ Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalJmp, Fast486ExtOpcodeConditionalSet, /* 0x90 - 0x9F */ Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodeConditionalSet, Fast486ExtOpcodePushFs, /* 0xA0 */ Fast486ExtOpcodePopFs, /* 0xA1 */ Fast486ExtOpcodeInvalid, /* 0xA2 */ // Invalid Fast486ExtOpcodeBitTest, /* 0xA3 */ Fast486ExtOpcodeShld, /* 0xA4 - 0xA5 */ Fast486ExtOpcodeShld, Fast486ExtOpcodeInvalid, /* 0xA6 - 0xA7 */ // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodePushGs, /* 0xA8 - 0xA9 */ Fast486ExtOpcodePopGs, Fast486ExtOpcodeInvalid, /* 0xAA */ // Invalid Fast486ExtOpcodeBts, /* 0xAB */ Fast486ExtOpcodeShrd, /* 0xAC - 0xAD */ Fast486ExtOpcodeShrd, Fast486ExtOpcodeInvalid, /* 0xAE */ // Invalid Fast486ExtOpcodeImul, /* 0xAF */ Fast486ExtOpcodeCmpXchgByte, /* 0xB0 */ Fast486ExtOpcodeCmpXchg, /* 0xB1 */ Fast486ExtOpcodeLss, /* 0xB2 */ Fast486ExtOpcodeBtr, /* 0xB3 */ Fast486ExtOpcodeLfsLgs, /* 0xB4 - 0xB5 */ Fast486ExtOpcodeLfsLgs, Fast486ExtOpcodeMovzxByte, /* 0xB6 - 0xB7 */ Fast486ExtOpcodeMovzxWord, Fast486ExtOpcodeInvalid, /* 0xB8 */ // Invalid Fast486ExtOpcodeGroup0FB9, /* 0xB9 */ Fast486ExtOpcodeGroup0FBA, /* 0xBA */ Fast486ExtOpcodeBtc, /* 0xBB */ Fast486ExtOpcodeBsf, /* 0xBC */ Fast486ExtOpcodeBsr, /* 0xBD */ Fast486ExtOpcodeMovsxByte, /* 0xBE - 0xBF */ Fast486ExtOpcodeMovsxWord, Fast486ExtOpcodeXaddByte, /* 0xC0 - 0xC1 */ Fast486ExtOpcodeXadd, Fast486ExtOpcodeInvalid, /* 0xC2 - 0xC7 */ // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeBswap, /* 0xC8 - 0xCF */ Fast486ExtOpcodeBswap, Fast486ExtOpcodeBswap, Fast486ExtOpcodeBswap, Fast486ExtOpcodeBswap, Fast486ExtOpcodeBswap, Fast486ExtOpcodeBswap, Fast486ExtOpcodeBswap, Fast486ExtOpcodeInvalid, /* 0xD0 - 0xFF */ // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid Fast486ExtOpcodeInvalid, // Invalid};
/* PUBLIC FUNCTIONS ***********************************************************/
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid){ DPRINT1("FAST486 -- Extended opcode 0x%02X is INVALID!\n", Opcode); Fast486Exception(State, FAST486_EXCEPTION_UD); return;}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented){ DPRINT1("FAST486 -- Extended opcode 0x%02X is UNIMPLEMENTED\n", Opcode); // Fast486Exception(State, FAST486_EXCEPTION_UD);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B){ /* Reserved opcode (UD2) */ Fast486Exception(State, FAST486_EXCEPTION_UD);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; BOOLEAN Valid; USHORT Selector; FAST486_GDT_ENTRY GdtEntry; DWORD AccessRights;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) || State->Flags.Vm) { /* Not recognized */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
NO_LOCK_PREFIX(); TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Value;
/* Read the value */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
Selector = LOWORD(Value); } else { /* Read the value */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector)) { /* Exception occurred */ return; } }
if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) { /* Exception occurred */ return; }
if (!Valid) { State->Flags.Zf = FALSE; return; }
/* Privilege check */ if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)) || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) { State->Flags.Zf = FALSE; return; }
/* Set ZF */ State->Flags.Zf = TRUE;
/* Get the access rights */ AccessRights = ((PDWORD)&GdtEntry)[1] & 0x00F0FF00;
/* Return the access rights */ if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, AccessRights); else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(AccessRights));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; BOOLEAN Valid; USHORT Selector; ULONG Limit; FAST486_GDT_ENTRY GdtEntry;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) || State->Flags.Vm) { /* Not recognized */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
NO_LOCK_PREFIX(); TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Value;
/* Read the value */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
Selector = LOWORD(Value); } else { /* Read the value */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector)) { /* Exception occurred */ return; } }
if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) { /* Exception occurred */ return; }
if (!Valid) { State->Flags.Zf = FALSE; return; }
/* Privilege check */ if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)) || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) { State->Flags.Zf = FALSE; return; }
/* Calculate the limit */ Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
if (GdtEntry.Granularity) { Limit <<= 12; Limit |= 0x00000FFF; }
/* Set ZF */ State->Flags.Zf = TRUE;
/* Return the limit */ if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Limit); else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(Limit));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts){ NO_LOCK_PREFIX();
/* The current privilege level must be zero */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
/* Clear the task switch bit */ State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg){ BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
NO_LOCK_PREFIX(); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* The current privilege level must be zero */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3)) { /* CR1, CR4, CR5, CR6 and CR7 don't exist */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (ModRegRm.Register != 0) { /* CR2 and CR3 and are stored in array indexes 1 and 2 */ ModRegRm.Register--; }
/* Store the value of the control register */ State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg){ BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
NO_LOCK_PREFIX(); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* The current privilege level must be zero */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7)) { /* DR6 and DR7 are aliases to DR4 and DR5 */ ModRegRm.Register -= 2; }
if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD) { /* Disallow access to debug registers */ Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
/* Store the value of the debug register */ State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg){ ULONG Value; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
NO_LOCK_PREFIX(); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* The current privilege level must be zero */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3)) { /* CR1, CR4, CR5, CR6 and CR7 don't exist */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (ModRegRm.Register != 0) { /* CR2 and CR3 and are stored in array indexes 1 and 2 */ ModRegRm.Register--; }
/* Get the value */ Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
if (ModRegRm.Register == (FAST486_GEN_REGS)FAST486_REG_CR0) { /* CR0 checks */
if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG) || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW)) { /* Invalid value */ Fast486Exception(State, FAST486_EXCEPTION_GP); return; } }
#ifndef FAST486_NO_PREFETCH /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */ State->PrefetchValid = FALSE;#endif
if (ModRegRm.Register == (FAST486_GEN_REGS)FAST486_REG_CR3) { /* Flush the TLB */ Fast486FlushTlb(State); }
/* Load a value to the control register */ State->ControlRegisters[ModRegRm.Register] = Value;}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg){ BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
NO_LOCK_PREFIX(); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* The current privilege level must be zero */ if (Fast486GetCurrentPrivLevel(State) != 0) { Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7)) { /* DR6 and DR7 are aliases to DR4 and DR5 */ ModRegRm.Register -= 2; }
if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD) { /* Disallow access to debug registers */ Fast486Exception(State, FAST486_EXCEPTION_GP); return; }
/* Load a value to the debug register */ State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
if (ModRegRm.Register == (FAST486_GEN_REGS)FAST486_REG_DR4) { /* The reserved bits are 1 */ State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED; } else if (ModRegRm.Register == (FAST486_GEN_REGS)FAST486_REG_DR5) { /* The reserved bits are 0 */ State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED; }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs){ /* Call the internal API */ Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs){ ULONG NewSelector;
if (!Fast486StackPop(State, &NewSelector)) { /* Exception occurred */ return; }
/* Call the internal API */ Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; UINT DataSize; ULONG BitNumber;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the number of bits */ if (OperandSize) DataSize = 32; else DataSize = 16;
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Get the bit number */ BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
if (ModRegRm.Memory) { /* * For memory operands, add the bit offset divided by * the data size to the address */ ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); }
/* Normalize the bit number */ BitNumber %= DataSize;
if (OperandSize) { ULONG Value;
/* Read the value */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1; } else { USHORT Value;
/* Read the value */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1; }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; UCHAR Count;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT((Opcode & 0xFE) == 0xA4);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (Opcode == 0xA4) { /* Fetch the count */ if (!Fast486FetchByte(State, &Count)) { /* Exception occurred */ return; } } else { /* The count is in CL */ Count = State->GeneralRegs[FAST486_REG_ECX].LowByte; }
/* Normalize the count */ Count &= 0x1F;
/* Do nothing if the count is zero */ if (Count == 0) return;
if (OperandSize) { ULONG Source, Destination, Result;
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = (Destination << Count) | (Source >> (32 - Count));
/* Update flags */ State->Flags.Cf = (Destination >> (32 - Count)) & 1; if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result); } else { USHORT Source, Destination, Result; ULONG DoubleSource;
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
DoubleSource = Source | (Source << 16);
/* Calculate the result */ Result = (Destination << Count) | (DoubleSource >> (32 - Count));
/* Update flags */ if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1; else State->Flags.Cf = (Source >> (32 - Count)) & 1;
if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs){ /* Call the internal API */ Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs){ ULONG NewSelector;
if (!Fast486StackPop(State, &NewSelector)) { /* Exception occurred */ return; }
/* Call the internal API */ Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; UINT DataSize; ULONG BitNumber;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the number of bits */ if (OperandSize) DataSize = 32; else DataSize = 16;
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Get the bit number */ BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
if (ModRegRm.Memory) { /* * For memory operands, add the bit offset divided by * the data size to the address */ ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); }
/* Normalize the bit number */ BitNumber %= DataSize;
if (OperandSize) { ULONG Value;
/* Read the value */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
/* Set the bit */ Value |= 1 << BitNumber;
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } else { USHORT Value;
/* Read the value */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
/* Set the bit */ Value |= 1 << BitNumber;
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; UCHAR Count;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT((Opcode & 0xFE) == 0xAC);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (Opcode == 0xAC) { /* Fetch the count */ if (!Fast486FetchByte(State, &Count)) { /* Exception occurred */ return; } } else { /* The count is in CL */ Count = State->GeneralRegs[FAST486_REG_ECX].LowByte; }
/* Normalize the count */ Count &= 0x1F;
/* Do nothing if the count is zero */ if (Count == 0) return;
if (OperandSize) { ULONG Source, Destination, Result;
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = (Destination >> Count) | (Source << (32 - Count));
/* Update flags */ State->Flags.Cf = (Destination >> (Count - 1)) & 1; if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result); } else { USHORT Source, Destination, Result;
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = (Destination >> Count) | (Source << (16 - Count));
if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
/* Update flags */ if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1; else State->Flags.Cf = (Source >> (Count - 17)) & 1;
if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (OperandSize) { LONG Source, Destination; LONGLONG Result;
/* Read the operands */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, (PULONG)&Destination, (PULONG)&Source)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = (LONGLONG)Source * (LONGLONG)Destination;
/* Update the flags */ State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result)); } else { SHORT Source, Destination; LONG Result;
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, (PUSHORT)&Destination, (PUSHORT)&Source)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = (LONG)Source * (LONG)Destination;
/* Update the flags */ State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result)); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte){ FAST486_MOD_REG_RM ModRegRm; UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte; UCHAR Source, Destination, Result; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Compare AL with the destination */ Result = Accumulator - Destination;
/* Update the flags */ State->Flags.Cf = (Accumulator < Destination); State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE)) && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE)); State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
if (State->Flags.Zf) { /* Load the source operand into the destination */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source); } else { /* Load the destination into AL */ State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination; }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Source, Destination, Result; ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
/* Read the operands */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Compare EAX with the destination */ Result = Accumulator - Destination;
/* Update the flags */ State->Flags.Cf = (Accumulator < Destination); State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG)) && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG)); State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
if (State->Flags.Zf) { /* Load the source operand into the destination */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source); } else { /* Load the destination into EAX */ State->GeneralRegs[FAST486_REG_EAX].Long = Destination; } } else { USHORT Source, Destination, Result; USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Compare AX with the destination */ Result = Accumulator - Destination;
/* Update the flags */ State->Flags.Cf = (Accumulator < Destination); State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD)) && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD)); State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
if (State->Flags.Zf) { /* Load the source operand into the destination */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source); } else { /* Load the destination into AX */ State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination; } }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss){ UCHAR FarPointer[6]; BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm;
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xB2);
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (!ModRegRm.Memory) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (!Fast486ReadMemory(State, (State->PrefixFlags & FAST486_PREFIX_SEG) ? State->SegmentOverride : FAST486_REG_DS, ModRegRm.MemoryAddress, FALSE, FarPointer, OperandSize ? 6 : 4)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Offset = *((PULONG)FarPointer); USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
/* Set the register to the offset */ State->GeneralRegs[ModRegRm.Register].Long = Offset;
/* Load the segment */ Fast486LoadSegment(State, FAST486_REG_SS, Segment); } else { USHORT Offset = *((PUSHORT)FarPointer); USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
/* Set the register to the offset */ State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
/* Load the segment */ Fast486LoadSegment(State, FAST486_REG_SS, Segment); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; UINT DataSize; ULONG BitNumber;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the number of bits */ if (OperandSize) DataSize = 32; else DataSize = 16;
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Get the bit number */ BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
if (ModRegRm.Memory) { /* * For memory operands, add the bit offset divided by * the data size to the address */ ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); }
/* Normalize the bit number */ BitNumber %= DataSize;
if (OperandSize) { ULONG Value;
/* Read the value */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
/* Clear the bit */ Value &= ~(1 << BitNumber);
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } else { USHORT Value;
/* Read the value */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
/* Clear the bit */ Value &= ~(1 << BitNumber);
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs){ UCHAR FarPointer[6]; BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm;
/* Make sure this is the right instruction */ ASSERT((Opcode & 0xFE) == 0xB4);
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (!ModRegRm.Memory) { /* Invalid */ Fast486Exception(State, FAST486_EXCEPTION_UD); return; }
if (!Fast486ReadMemory(State, (State->PrefixFlags & FAST486_PREFIX_SEG) ? State->SegmentOverride : FAST486_REG_DS, ModRegRm.MemoryAddress, FALSE, FarPointer, OperandSize ? 6 : 4)) { /* Exception occurred */ return; }
if (OperandSize) { ULONG Offset = *((PULONG)FarPointer); USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
/* Set the register to the offset */ State->GeneralRegs[ModRegRm.Register].Long = Offset;
/* Load the segment */ Fast486LoadSegment(State, (Opcode == 0xB4) ? FAST486_REG_FS : FAST486_REG_GS, Segment); } else { USHORT Offset = *((PUSHORT)FarPointer); USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
/* Set the register to the offset */ State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
/* Load the segment */ Fast486LoadSegment(State, (Opcode == 0xB4) ? FAST486_REG_FS : FAST486_REG_GS, Segment); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte){ UCHAR Value; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xB6);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Write back the zero-extended value */ Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)Value);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord){ USHORT Value; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xB7);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Write back the zero-extended value */ Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)Value);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc){ BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; UINT DataSize; ULONG BitNumber;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Get the number of bits */ if (OperandSize) DataSize = 32; else DataSize = 16;
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Get the bit number */ BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
if (ModRegRm.Memory) { /* * For memory operands, add the bit offset divided by * the data size to the address */ ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8); }
/* Normalize the bit number */ BitNumber %= DataSize;
if (OperandSize) { ULONG Value;
/* Read the value */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
/* Toggle the bit */ Value ^= 1 << BitNumber;
/* Write back the result */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value); } else { USHORT Value;
/* Read the value */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; }
/* Set CF to the bit value */ State->Flags.Cf = (Value >> BitNumber) & 1;
/* Toggle the bit */ Value ^= 1 << BitNumber;
/* Write back the result */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf){ UINT i; ULONG Value = 0; BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; ULONG BitNumber; UINT DataSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xBC);
/* Get the number of bits */ if (OperandSize) DataSize = 32; else DataSize = 16;
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the value */ if (OperandSize) { if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; } } else { if (!Fast486ReadModrmWordOperands(State, &ModRegRm, (PUSHORT)NULL, (PUSHORT)&Value)) { /* Exception occurred */ return; } }
/* Set ZF */ State->Flags.Zf = (Value == 0); if (State->Flags.Zf) return;
for (i = 0; i < DataSize; i++) { if (Value & (1 << i)) { /* Save the bit number */ BitNumber = i;
/* Exit the loop */ break; } }
/* Write back the result */ if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber); else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr){ INT i; ULONG Value = 0; BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; ULONG BitNumber; UINT DataSize;
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xBD);
/* Get the number of bits */ if (OperandSize) DataSize = 32; else DataSize = 16;
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the value */ if (OperandSize) { if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { /* Exception occurred */ return; } } else { if (!Fast486ReadModrmWordOperands(State, &ModRegRm, (PUSHORT)NULL, (PUSHORT)&Value)) { /* Exception occurred */ return; } }
/* Set ZF according to the value */ State->Flags.Zf = (Value == 0); if (State->Flags.Zf) return;
for (i = DataSize - 1; i >= 0; i--) { if (Value & (1 << i)) { /* Save the bit number */ BitNumber = i;
/* Exit the loop */ break; } }
/* Write back the result */ if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber); else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte){ CHAR Value; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xBE);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value)) { /* Exception occurred */ return; }
/* Write back the sign-extended value */ Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Value));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord){ SHORT Value; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
TOGGLE_ADSIZE(AddressSize);
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xBF);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Read the operands */ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value)) { /* Exception occurred */ return; }
/* Write back the sign-extended value */ Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Value));}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp){ BOOLEAN Jump = FALSE; LONG Offset = 0; BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_OPSIZE(Size); NO_LOCK_PREFIX();
/* Make sure this is the right instruction */ ASSERT((Opcode & 0xF0) == 0x80);
/* Fetch the offset */ if (Size) { if (!Fast486FetchDword(State, (PULONG)&Offset)) { /* Exception occurred */ return; } } else { SHORT Value;
if (!Fast486FetchWord(State, (PUSHORT)&Value)) { /* Exception occurred */ return; }
/* Sign-extend */ Offset = (LONG)Value; }
switch ((Opcode & 0x0F) >> 1) { /* JO / JNO */ case 0: { Jump = State->Flags.Of; break; }
/* JC / JNC */ case 1: { Jump = State->Flags.Cf; break; }
/* JZ / JNZ */ case 2: { Jump = State->Flags.Zf; break; }
/* JBE / JNBE */ case 3: { Jump = State->Flags.Cf || State->Flags.Zf; break; }
/* JS / JNS */ case 4: { Jump = State->Flags.Sf; break; }
/* JP / JNP */ case 5: { Jump = State->Flags.Pf; break; }
/* JL / JNL */ case 6: { Jump = State->Flags.Sf != State->Flags.Of; break; }
/* JLE / JNLE */ case 7: { Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf; break; } }
if (Opcode & 1) { /* Invert the result */ Jump = !Jump; }
if (Jump) { /* Move the instruction pointer */ State->InstPtr.Long += Offset; }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet){ BOOLEAN Value = FALSE; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; FAST486_MOD_REG_RM ModRegRm;
TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Make sure this is the right instruction */ ASSERT((Opcode & 0xF0) == 0x90);
switch ((Opcode & 0x0F) >> 1) { /* SETO / SETNO */ case 0: { Value = State->Flags.Of; break; }
/* SETC / SETNC */ case 1: { Value = State->Flags.Cf; break; }
/* SETZ / SETNZ */ case 2: { Value = State->Flags.Zf; break; }
/* SETBE / SETNBE */ case 3: { Value = State->Flags.Cf || State->Flags.Zf; break; }
/* SETS / SETNS */ case 4: { Value = State->Flags.Sf; break; }
/* SETP / SETNP */ case 5: { Value = State->Flags.Pf; break; }
/* SETL / SETNL */ case 6: { Value = State->Flags.Sf != State->Flags.Of; break; }
/* SETLE / SETNLE */ case 7: { Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf; break; } }
if (Opcode & 1) { /* Invert the result */ Value = !Value; }
/* Write back the result */ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte){ UCHAR Source, Destination, Result; FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xC0);
TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = Source + Destination;
/* Update the flags */ State->Flags.Cf = (Result < Source) && (Result < Destination); State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE)) && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE)); State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write the sum to the destination */ if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result)) { /* Exception occurred */ return; }
/* Write the old value of the destination to the source */ Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination);}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd){ FAST486_MOD_REG_RM ModRegRm; BOOLEAN OperandSize, AddressSize;
/* Make sure this is the right instruction */ ASSERT(Opcode == 0xC1);
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
TOGGLE_ADSIZE(AddressSize); TOGGLE_OPSIZE(OperandSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { /* Exception occurred */ return; }
/* Check the operand size */ if (OperandSize) { ULONG Source, Destination, Result;
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = Source + Destination;
/* Update the flags */ State->Flags.Cf = (Result < Source) && (Result < Destination); State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG)) && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG)); State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write the old value of the destination to the source */ if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination)) { /* Exception occurred */ return; }
/* Write the sum to the destination */ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result); } else { USHORT Source, Destination, Result;
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination)) { /* Exception occurred */ return; }
/* Calculate the result */ Result = Source + Destination;
/* Update the flags */ State->Flags.Cf = (Result < Source) && (Result < Destination); State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD)) && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD)); State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0); State->Flags.Zf = (Result == 0); State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0); State->Flags.Pf = Fast486CalculateParity(Result);
/* Write the old value of the destination to the source */ if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination)) { /* Exception occurred */ return; }
/* Write the sum to the destination */ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result); }}
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap){ PUCHAR Pointer;
NO_LOCK_PREFIX();
/* Get a pointer to the value */ Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
/* Swap the byte order */ SWAP(Pointer[0], Pointer[3]); SWAP(Pointer[1], Pointer[2]);}
FAST486_OPCODE_HANDLER(Fast486OpcodeExtended){ UCHAR SecondOpcode;
/* Fetch the second operation code */ if (!Fast486FetchByte(State, &SecondOpcode)) { /* Exception occurred */ return; }
/* Call the extended opcode handler */ Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);}
/* EOF */