Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314/* * Fast486 386/486 CPU Emulation Library * common.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 "common.h"
/* PUBLIC FUNCTIONS ***********************************************************/
BOOLEANFASTCALLFast486ReadMemory(PFAST486_STATE State, FAST486_SEG_REGS SegmentReg, ULONG Offset, BOOLEAN InstFetch, PVOID Buffer, ULONG Size){ ULONG LinearAddress; PFAST486_SEG_REG CachedDescriptor; FAST486_EXCEPTIONS Exception = SegmentReg != FAST486_REG_SS ? FAST486_EXCEPTION_GP : FAST486_EXCEPTION_SS;
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
/* Get the cached descriptor */ CachedDescriptor = &State->SegmentRegs[SegmentReg];
if (InstFetch || CachedDescriptor->Executable || !CachedDescriptor->DirConf) { if ((Offset + Size - 1) > CachedDescriptor->Limit) { /* Read beyond limit */ Fast486Exception(State, Exception); return FALSE; } } else { if (Offset < CachedDescriptor->Limit) { /* Read beyond limit */ Fast486Exception(State, Exception); return FALSE; } }
/* Check for protected mode */ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) { /* Privilege checks */
if (!CachedDescriptor->Present) { Fast486Exception(State, Exception); return FALSE; }
if ((!InstFetch && (CachedDescriptor->Rpl > CachedDescriptor->Dpl)) || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl)) { Fast486Exception(State, Exception); return FALSE; }
if (InstFetch) { if (!CachedDescriptor->Executable) { /* Data segment not executable */ Fast486Exception(State, Exception); return FALSE; } } else { if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite)) { /* Code segment not readable */ Fast486Exception(State, Exception); return FALSE; } } }
/* Find the linear address */ LinearAddress = CachedDescriptor->Base + Offset;
#ifndef FAST486_NO_PREFETCH if (InstFetch && ((Offset + FAST486_CACHE_SIZE - 1) <= CachedDescriptor->Limit)) { State->PrefetchAddress = LinearAddress;
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG) && (PAGE_OFFSET(State->PrefetchAddress) > (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE))) { /* We mustn't prefetch across a page boundary */ State->PrefetchAddress = PAGE_ALIGN(State->PrefetchAddress) | (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE);
if ((LinearAddress - State->PrefetchAddress + Size) >= FAST486_CACHE_SIZE) { /* We can't prefetch without possibly violating page permissions */ State->PrefetchValid = FALSE; return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size, TRUE); } }
/* Prefetch */ if (Fast486ReadLinearMemory(State, State->PrefetchAddress, State->PrefetchCache, FAST486_CACHE_SIZE, TRUE)) { State->PrefetchValid = TRUE;
RtlMoveMemory(Buffer, &State->PrefetchCache[LinearAddress - State->PrefetchAddress], Size); return TRUE; } else { State->PrefetchValid = FALSE; return FALSE; } } else#endif { /* Read from the linear address */ return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size, TRUE); }}
BOOLEANFASTCALLFast486WriteMemory(PFAST486_STATE State, FAST486_SEG_REGS SegmentReg, ULONG Offset, PVOID Buffer, ULONG Size){ ULONG LinearAddress; PFAST486_SEG_REG CachedDescriptor; FAST486_EXCEPTIONS Exception = SegmentReg != FAST486_REG_SS ? FAST486_EXCEPTION_GP : FAST486_EXCEPTION_SS;
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
/* Get the cached descriptor */ CachedDescriptor = &State->SegmentRegs[SegmentReg];
if (CachedDescriptor->Executable || !CachedDescriptor->DirConf) { if ((Offset + Size - 1) > CachedDescriptor->Limit) { /* Write beyond limit */ Fast486Exception(State, Exception); return FALSE; } } else { if (Offset < CachedDescriptor->Limit) { /* Write beyond limit */ Fast486Exception(State, Exception); return FALSE; } }
/* Check for protected mode */ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) { /* Privilege checks */
if (!CachedDescriptor->Present) { Fast486Exception(State, Exception); return FALSE; }
if ((CachedDescriptor->Rpl > CachedDescriptor->Dpl) || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl)) { Fast486Exception(State, Exception); return FALSE; }
if (CachedDescriptor->Executable) { /* Code segment not writable */ Fast486Exception(State, Exception); return FALSE; } else if (!CachedDescriptor->ReadWrite) { /* Data segment not writeable */ Fast486Exception(State, Exception); return FALSE; } }
/* Find the linear address */ LinearAddress = CachedDescriptor->Base + Offset;
#ifndef FAST486_NO_PREFETCH if (State->PrefetchValid && (LinearAddress >= State->PrefetchAddress) && ((LinearAddress + Size) <= (State->PrefetchAddress + FAST486_CACHE_SIZE))) { /* Update the prefetch */ RtlMoveMemory(&State->PrefetchCache[LinearAddress - State->PrefetchAddress], Buffer, min(Size, FAST486_CACHE_SIZE + State->PrefetchAddress - LinearAddress)); }#endif
/* Write to the linear address */ return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size, TRUE);}
static inline BOOLEANFASTCALLFast486GetIntVector(PFAST486_STATE State, UCHAR Number, PFAST486_IDT_ENTRY IdtEntry){ /* Check for protected mode */ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) { /* Read from the IDT */ if (!Fast486ReadLinearMemory(State, State->Idtr.Address + Number * sizeof(*IdtEntry), IdtEntry, sizeof(*IdtEntry), FALSE)) { /* Exception occurred */ return FALSE; } } else { /* Read from the real-mode IVT */ ULONG FarPointer;
/* Paging is always disabled in real mode */ State->MemReadCallback(State, State->Idtr.Address + Number * sizeof(FarPointer), &FarPointer, sizeof(FarPointer));
/* Fill a fake IDT entry */ IdtEntry->Offset = LOWORD(FarPointer); IdtEntry->Selector = HIWORD(FarPointer); IdtEntry->Zero = 0; IdtEntry->Type = FAST486_IDT_INT_GATE; IdtEntry->Storage = FALSE; IdtEntry->Dpl = 0; IdtEntry->Present = TRUE; IdtEntry->OffsetHigh = 0; }
return TRUE;}
static inline BOOLEANFASTCALLFast486InterruptInternal(PFAST486_STATE State, PFAST486_IDT_ENTRY IdtEntry, BOOLEAN PushErrorCode, ULONG ErrorCode){ BOOLEAN GateSize = (IdtEntry->Type == FAST486_IDT_INT_GATE_32) || (IdtEntry->Type == FAST486_IDT_TRAP_GATE_32); USHORT OldCs = State->SegmentRegs[FAST486_REG_CS].Selector; ULONG OldEip = State->InstPtr.Long; ULONG OldFlags = State->Flags.Long; UCHAR OldCpl = State->Cpl;
/* Check for protected mode */ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) { USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector; ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long; BOOLEAN OldVm = State->Flags.Vm;
if (IdtEntry->Type == FAST486_TASK_GATE_SIGNATURE) { /* Task call */ if (!Fast486TaskSwitch(State, FAST486_TASK_CALL, IdtEntry->Selector)) { /* Exception occurred */ return FALSE; }
goto Finish; }
/* Check if the interrupt handler is more privileged or if we're in V86 mode */ if ((OldCpl > GET_SEGMENT_RPL(IdtEntry->Selector)) || State->Flags.Vm) { FAST486_TSS Tss; PFAST486_LEGACY_TSS LegacyTss = (PFAST486_LEGACY_TSS)&Tss; USHORT NewSs; ULONG NewEsp;
/* Read the TSS */ if (!Fast486ReadLinearMemory(State, State->TaskReg.Base, &Tss, State->TaskReg.Modern ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS), FALSE)) { /* Exception occurred */ return FALSE; }
/* Switch to the new privilege level */ State->Cpl = GET_SEGMENT_RPL(IdtEntry->Selector);
/* Clear the VM flag */ State->Flags.Vm = FALSE;
/* Check the new (higher) privilege level */ switch (State->Cpl) { case 0: { if (State->TaskReg.Modern) { NewSs = Tss.Ss0; NewEsp = Tss.Esp0; } else { NewSs = LegacyTss->Ss0; NewEsp = LegacyTss->Sp0; }
break; }
case 1: { if (State->TaskReg.Modern) { NewSs = Tss.Ss1; NewEsp = Tss.Esp1; } else { NewSs = LegacyTss->Ss1; NewEsp = LegacyTss->Sp1; }
break; }
case 2: { if (State->TaskReg.Modern) { NewSs = Tss.Ss2; NewEsp = Tss.Esp2; } else { NewSs = LegacyTss->Ss2; NewEsp = LegacyTss->Sp2; }
break; }
default: { /* Should never reach here! */ ASSERT(FALSE); } }
if (!Fast486LoadSegment(State, FAST486_REG_SS, NewSs)) { /* Exception occurred */ return FALSE; }
State->GeneralRegs[FAST486_REG_ESP].Long = NewEsp; }
/* Load new CS */ if (!Fast486LoadSegment(State, FAST486_REG_CS, IdtEntry->Selector)) { /* An exception occurred during the jump */ return FALSE; }
if (GateSize) { /* 32-bit code segment, use EIP */ State->InstPtr.Long = MAKELONG(IdtEntry->Offset, IdtEntry->OffsetHigh); } else { /* 16-bit code segment, use IP */ State->InstPtr.LowWord = IdtEntry->Offset; }
/* Clear NT */ State->Flags.Nt = FALSE;
if (OldVm) { /* Push GS, FS, DS and ES */ if (!Fast486StackPushInternal(State, GateSize, State->SegmentRegs[FAST486_REG_GS].Selector)) { return FALSE; } if (!Fast486StackPushInternal(State, GateSize, State->SegmentRegs[FAST486_REG_FS].Selector)) { return FALSE; } if (!Fast486StackPushInternal(State, GateSize, State->SegmentRegs[FAST486_REG_DS].Selector)) { return FALSE; } if (!Fast486StackPushInternal(State, GateSize, State->SegmentRegs[FAST486_REG_ES].Selector)) { return FALSE; }
/* Now load them with NULL selectors, since they are useless in protected mode */ if (!Fast486LoadSegment(State, FAST486_REG_GS, 0)) return FALSE; if (!Fast486LoadSegment(State, FAST486_REG_FS, 0)) return FALSE; if (!Fast486LoadSegment(State, FAST486_REG_DS, 0)) return FALSE; if (!Fast486LoadSegment(State, FAST486_REG_ES, 0)) return FALSE; }
/* Check if the interrupt handler is more privileged or we're in VM86 mode (again) */ if ((OldCpl > GET_SEGMENT_RPL(IdtEntry->Selector)) || OldVm) { /* Push SS selector */ if (!Fast486StackPushInternal(State, GateSize, OldSs)) return FALSE;
/* Push the stack pointer */ if (!Fast486StackPushInternal(State, GateSize, OldEsp)) return FALSE; } } else { /* Load new CS */ if (!Fast486LoadSegment(State, FAST486_REG_CS, IdtEntry->Selector)) { /* An exception occurred during the jump */ return FALSE; }
/* Set the new IP */ State->InstPtr.LowWord = IdtEntry->Offset; }
/* Push EFLAGS */ if (!Fast486StackPushInternal(State, GateSize, OldFlags)) return FALSE;
/* Push CS selector */ if (!Fast486StackPushInternal(State, GateSize, OldCs)) return FALSE;
/* Push the instruction pointer */ if (!Fast486StackPushInternal(State, GateSize, OldEip)) return FALSE;
Finish:
if (PushErrorCode) { /* Push the error code */ if (!Fast486StackPushInternal(State, GateSize, ErrorCode)) return FALSE; }
if ((IdtEntry->Type == FAST486_IDT_INT_GATE) || (IdtEntry->Type == FAST486_IDT_INT_GATE_32)) { /* Disable interrupts after a jump to an interrupt gate handler */ State->Flags.If = FALSE; }
/* Clear TF */ State->Flags.Tf = FALSE;
return TRUE;}
BOOLEANFASTCALLFast486PerformInterrupt(PFAST486_STATE State, UCHAR Number){ FAST486_IDT_ENTRY IdtEntry;
/* Get the interrupt vector */ if (!Fast486GetIntVector(State, Number, &IdtEntry)) { /* Exception occurred */ return FALSE; }
/* Perform the interrupt */ if (!Fast486InterruptInternal(State, &IdtEntry, FALSE, 0)) { /* Exception occurred */ return FALSE; }
return TRUE;}
VOIDFASTCALLFast486ExceptionWithErrorCode(PFAST486_STATE State, FAST486_EXCEPTIONS ExceptionCode, ULONG ErrorCode){ FAST486_IDT_ENTRY IdtEntry;
/* Increment the exception count */ State->ExceptionCount++;
/* Check if the exception occurred more than once */ if (State->ExceptionCount > 1) { /* Then this is a double fault */ ExceptionCode = FAST486_EXCEPTION_DF; }
/* Check if this is a triple fault */ if (State->ExceptionCount == 3) { DPRINT("Fast486ExceptionWithErrorCode(%04X:%08X) -- Triple fault\n", State->SegmentRegs[FAST486_REG_CS].Selector, State->InstPtr.Long);
/* Reset the CPU */ Fast486Reset(State); return; }
/* Clear the prefix flags */ State->PrefixFlags = 0;
/* Restore the IP to the saved IP */ State->InstPtr = State->SavedInstPtr;
/* Restore the SP to the saved SP */ State->GeneralRegs[FAST486_REG_ESP] = State->SavedStackPtr;
/* Get the interrupt vector */ if (!Fast486GetIntVector(State, ExceptionCode, &IdtEntry)) { /* * If this function failed, that means Fast486Exception * was called again, so just return in this case. */ return; }
/* Perform the interrupt */ if (!Fast486InterruptInternal(State, &IdtEntry, EXCEPTION_HAS_ERROR_CODE(ExceptionCode) && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE), ErrorCode)) { /* * If this function failed, that means Fast486Exception * was called again, so just return in this case. */ return; }
/* Reset the exception count */ State->ExceptionCount = 0;}
BOOLEANFASTCALLFast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Selector){ ULONG NewTssAddress; ULONG NewTssLimit; FAST486_SYSTEM_DESCRIPTOR NewTssDescriptor; FAST486_TSS OldTss; PFAST486_LEGACY_TSS OldLegacyTss = (PFAST486_LEGACY_TSS)&OldTss; FAST486_TSS NewTss; PFAST486_LEGACY_TSS NewLegacyTss = (PFAST486_LEGACY_TSS)&NewTss; USHORT NewLdtr, NewEs, NewCs, NewSs, NewDs;
if ((State->TaskReg.Modern && State->TaskReg.Limit < (sizeof(FAST486_TSS) - 1)) || (!State->TaskReg.Modern && State->TaskReg.Limit < (sizeof(FAST486_LEGACY_TSS) - 1))) { /* Invalid task register limit */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, State->TaskReg.Selector); return FALSE; }
/* Read the old TSS */ if (!Fast486ReadLinearMemory(State, State->TaskReg.Base, &OldTss, State->TaskReg.Modern ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS), FALSE)) { /* Exception occurred */ return FALSE; }
/* If this is a task return, use the linked previous selector */ if (Type == FAST486_TASK_RETURN) { if (State->TaskReg.Modern) Selector = LOWORD(OldTss.Link); else Selector = OldLegacyTss->Link; }
/* Make sure the entry exists in the GDT (not LDT!) */ if ((GET_SEGMENT_INDEX(Selector) == 0) || (Selector & SEGMENT_TABLE_INDICATOR) || GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u)) { Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector); return FALSE; }
/* Get the TSS descriptor from the GDT */ if (!Fast486ReadLinearMemory(State, State->Gdtr.Address + GET_SEGMENT_INDEX(Selector), &NewTssDescriptor, sizeof(NewTssDescriptor), FALSE)) { /* Exception occurred */ return FALSE; }
if (!NewTssDescriptor.Present) { /* Incoming task TSS not present */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); return FALSE; }
/* Calculate the linear address of the new TSS */ NewTssAddress = NewTssDescriptor.Base; NewTssAddress |= NewTssDescriptor.BaseMid << 16; NewTssAddress |= NewTssDescriptor.BaseHigh << 24;
/* Calculate the limit of the new TSS */ NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16);
if (NewTssDescriptor.Granularity) { NewTssLimit <<= 12; NewTssLimit |= 0x00000FFF; }
if (NewTssLimit < (sizeof(FAST486_TSS) - 1) && NewTssLimit != (sizeof(FAST486_LEGACY_TSS) - 1)) { /* TSS limit invalid */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector); return FALSE; }
/* * The incoming task shouldn't be busy if we're executing it as a * new task, and it should be busy if we're returning to it. */ if ((((NewTssDescriptor.Signature != FAST486_TSS_SIGNATURE) && (NewTssDescriptor.Signature != FAST486_TSS_16_SIGNATURE)) || (Type == FAST486_TASK_RETURN)) && (((NewTssDescriptor.Signature != FAST486_BUSY_TSS_SIGNATURE) && (NewTssDescriptor.Signature != FAST486_BUSY_TSS_16_SIGNATURE)) || (Type != FAST486_TASK_RETURN))) { Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return FALSE; }
/* Read the new TSS */ if (!Fast486ReadLinearMemory(State, NewTssAddress, &NewTss, (NewTssDescriptor.Signature == FAST486_TSS_SIGNATURE) || (NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE) ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS), FALSE)) { /* Exception occurred */ return FALSE; }
if (Type != FAST486_TASK_CALL) { /* Clear the busy bit of the outgoing task */ FAST486_SYSTEM_DESCRIPTOR OldTssDescriptor;
if (!Fast486ReadLinearMemory(State, State->Gdtr.Address + GET_SEGMENT_INDEX(State->TaskReg.Selector), &OldTssDescriptor, sizeof(OldTssDescriptor), FALSE)) { /* Exception occurred */ return FALSE; }
OldTssDescriptor.Signature = FAST486_TSS_SIGNATURE;
if (!Fast486WriteLinearMemory(State, State->Gdtr.Address + GET_SEGMENT_INDEX(State->TaskReg.Selector), &OldTssDescriptor, sizeof(OldTssDescriptor), FALSE)) { /* Exception occurred */ return FALSE; } } else { /* Store the link */ if ((NewTssDescriptor.Signature == FAST486_TSS_SIGNATURE) || (NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE)) { NewTss.Link = State->TaskReg.Selector;
/* Write back the new TSS link */ if (!Fast486WriteLinearMemory(State, NewTssAddress, &NewTss.Link, sizeof(NewTss.Link), FALSE)) { /* Exception occurred */ return FALSE; } } else { NewLegacyTss->Link = State->TaskReg.Selector;
/* Write back the new legacy TSS link */ if (!Fast486WriteLinearMemory(State, NewTssAddress, &NewLegacyTss->Link, sizeof(NewLegacyTss->Link), FALSE)) { /* Exception occurred */ return FALSE; } } }
/* Save the current task into the TSS */ if (State->TaskReg.Modern) { OldTss.Cr3 = State->ControlRegisters[FAST486_REG_CR3]; OldTss.Eip = State->InstPtr.Long; OldTss.Eflags = State->Flags.Long; OldTss.Eax = State->GeneralRegs[FAST486_REG_EAX].Long; OldTss.Ecx = State->GeneralRegs[FAST486_REG_ECX].Long; OldTss.Edx = State->GeneralRegs[FAST486_REG_EDX].Long; OldTss.Ebx = State->GeneralRegs[FAST486_REG_EBX].Long; OldTss.Esp = State->GeneralRegs[FAST486_REG_ESP].Long; OldTss.Ebp = State->GeneralRegs[FAST486_REG_EBP].Long; OldTss.Esi = State->GeneralRegs[FAST486_REG_ESI].Long; OldTss.Edi = State->GeneralRegs[FAST486_REG_EDI].Long; OldTss.Es = State->SegmentRegs[FAST486_REG_ES].Selector; OldTss.Cs = State->SegmentRegs[FAST486_REG_CS].Selector; OldTss.Ss = State->SegmentRegs[FAST486_REG_SS].Selector; OldTss.Ds = State->SegmentRegs[FAST486_REG_DS].Selector; OldTss.Fs = State->SegmentRegs[FAST486_REG_FS].Selector; OldTss.Gs = State->SegmentRegs[FAST486_REG_GS].Selector; OldTss.Ldtr = State->Ldtr.Selector; } else { OldLegacyTss->Ip = State->InstPtr.LowWord; OldLegacyTss->Flags = State->Flags.LowWord; OldLegacyTss->Ax = State->GeneralRegs[FAST486_REG_EAX].LowWord; OldLegacyTss->Cx = State->GeneralRegs[FAST486_REG_ECX].LowWord; OldLegacyTss->Dx = State->GeneralRegs[FAST486_REG_EDX].LowWord; OldLegacyTss->Bx = State->GeneralRegs[FAST486_REG_EBX].LowWord; OldLegacyTss->Sp = State->GeneralRegs[FAST486_REG_ESP].LowWord; OldLegacyTss->Bp = State->GeneralRegs[FAST486_REG_EBP].LowWord; OldLegacyTss->Si = State->GeneralRegs[FAST486_REG_ESI].LowWord; OldLegacyTss->Di = State->GeneralRegs[FAST486_REG_EDI].LowWord; OldLegacyTss->Es = State->SegmentRegs[FAST486_REG_ES].Selector; OldLegacyTss->Cs = State->SegmentRegs[FAST486_REG_CS].Selector; OldLegacyTss->Ss = State->SegmentRegs[FAST486_REG_SS].Selector; OldLegacyTss->Ds = State->SegmentRegs[FAST486_REG_DS].Selector; OldLegacyTss->Ldtr = State->Ldtr.Selector; }
/* Write back the old TSS */ if (!Fast486WriteLinearMemory(State, State->TaskReg.Base, &OldTss, State->TaskReg.Modern ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS), FALSE)) { /* Exception occurred */ return FALSE; }
/* Mark the new task as busy */ if (NewTssDescriptor.Signature == FAST486_TSS_SIGNATURE || NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE) { /* 32-bit TSS */ NewTssDescriptor.Signature = FAST486_BUSY_TSS_SIGNATURE; } else { /* 16-bit TSS */ NewTssDescriptor.Signature = FAST486_BUSY_TSS_16_SIGNATURE; }
/* Write back the new TSS descriptor */ if (!Fast486WriteLinearMemory(State, State->Gdtr.Address + GET_SEGMENT_INDEX(Selector), &NewTssDescriptor, sizeof(NewTssDescriptor), FALSE)) { /* Exception occurred */ return FALSE; }
/* Set the task switch bit */ State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_TS;
/* Load the task register with the new values */ State->TaskReg.Selector = Selector; State->TaskReg.Base = NewTssAddress; State->TaskReg.Limit = NewTssLimit; State->TaskReg.Modern = (NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE);
if (NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE) { /* Change the page directory */ State->ControlRegisters[FAST486_REG_CR3] = NewTss.Cr3; }
/* Flush the TLB */ Fast486FlushTlb(State);
/* Update the CPL */ if (NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE) { State->Cpl = GET_SEGMENT_RPL(NewTss.Cs); } else { State->Cpl = GET_SEGMENT_RPL(NewLegacyTss->Cs); }
#ifndef FAST486_NO_PREFETCH /* Context switching invalidates the prefetch */ State->PrefetchValid = FALSE;#endif
/* Load the registers */ if (NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE) { State->InstPtr.Long = State->SavedInstPtr.Long = NewTss.Eip; State->Flags.Long = NewTss.Eflags; State->GeneralRegs[FAST486_REG_EAX].Long = NewTss.Eax; State->GeneralRegs[FAST486_REG_ECX].Long = NewTss.Ecx; State->GeneralRegs[FAST486_REG_EDX].Long = NewTss.Edx; State->GeneralRegs[FAST486_REG_EBX].Long = NewTss.Ebx; State->GeneralRegs[FAST486_REG_EBP].Long = NewTss.Ebp; State->GeneralRegs[FAST486_REG_ESI].Long = NewTss.Esi; State->GeneralRegs[FAST486_REG_EDI].Long = NewTss.Edi; NewEs = NewTss.Es; NewCs = NewTss.Cs; NewDs = NewTss.Ds; NewLdtr = NewTss.Ldtr;
if (Type == FAST486_TASK_CALL && State->Cpl < 3) { switch (State->Cpl) { case 0: { State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp0; NewSs = NewTss.Ss0; break; }
case 1: { State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp1; NewSs = NewTss.Ss1; break; }
case 2: { State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp2; NewSs = NewTss.Ss2; break; } } } else { State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp; NewSs = NewTss.Ss; } } else { State->InstPtr.LowWord = State->SavedInstPtr.LowWord = NewLegacyTss->Ip; State->Flags.LowWord = NewLegacyTss->Flags; State->GeneralRegs[FAST486_REG_EAX].LowWord = NewLegacyTss->Ax; State->GeneralRegs[FAST486_REG_ECX].LowWord = NewLegacyTss->Cx; State->GeneralRegs[FAST486_REG_EDX].LowWord = NewLegacyTss->Dx; State->GeneralRegs[FAST486_REG_EBX].LowWord = NewLegacyTss->Bx; State->GeneralRegs[FAST486_REG_EBP].LowWord = NewLegacyTss->Bp; State->GeneralRegs[FAST486_REG_ESI].LowWord = NewLegacyTss->Si; State->GeneralRegs[FAST486_REG_EDI].LowWord = NewLegacyTss->Di; NewEs = NewLegacyTss->Es; NewCs = NewLegacyTss->Cs; NewDs = NewLegacyTss->Ds; NewLdtr = NewLegacyTss->Ldtr;
if (Type == FAST486_TASK_CALL && State->Cpl < 3) { switch (State->Cpl) { case 0: { State->GeneralRegs[FAST486_REG_ESP].Long = NewLegacyTss->Sp0; NewSs = NewLegacyTss->Ss0; break; }
case 1: { State->GeneralRegs[FAST486_REG_ESP].Long = NewLegacyTss->Sp1; NewSs = NewLegacyTss->Ss1; break; }
case 2: { State->GeneralRegs[FAST486_REG_ESP].Long = NewLegacyTss->Sp2; NewSs = NewLegacyTss->Ss2; break; } } } else { State->GeneralRegs[FAST486_REG_ESP].Long = NewLegacyTss->Sp; NewSs = NewLegacyTss->Ss; } }
/* Set the NT flag if nesting */ if (Type == FAST486_TASK_CALL) State->Flags.Nt = TRUE;
if (GET_SEGMENT_INDEX(NewLdtr) != 0) { BOOLEAN Valid; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
if (NewLdtr & SEGMENT_TABLE_INDICATOR) { /* This selector doesn't point to the GDT */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr); return FALSE; }
if (!Fast486ReadDescriptorEntry(State, NewLdtr, &Valid, (PFAST486_GDT_ENTRY)&GdtEntry)) { /* Exception occurred */ return FALSE; }
if (!Valid) { /* Invalid selector */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr); return FALSE; }
if (GdtEntry.Signature != FAST486_LDT_SIGNATURE) { /* This is not an LDT descriptor */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr); return FALSE; }
if (!GdtEntry.Present) { Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr); return FALSE; }
/* Update the LDTR */ State->Ldtr.Selector = NewLdtr; State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
if (GdtEntry.Granularity) { State->Ldtr.Limit <<= 12; State->Ldtr.Limit |= 0x00000FFF; } } else { /* The LDT of this task is empty */ RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr)); }
/* Load the new segments */ if (!Fast486LoadSegmentInternal(State, FAST486_REG_CS, NewCs, FAST486_EXCEPTION_TS)) { return FALSE; }
if (!Fast486LoadSegmentInternal(State, FAST486_REG_SS, NewSs, FAST486_EXCEPTION_TS)) { return FALSE; }
if (!Fast486LoadSegmentInternal(State, FAST486_REG_ES, NewEs, FAST486_EXCEPTION_TS)) { return FALSE; }
if (!Fast486LoadSegmentInternal(State, FAST486_REG_DS, NewDs, FAST486_EXCEPTION_TS)) { return FALSE; }
if (NewTssDescriptor.Signature == FAST486_BUSY_TSS_SIGNATURE) { if (!Fast486LoadSegmentInternal(State, FAST486_REG_FS, NewTss.Fs, FAST486_EXCEPTION_TS)) { return FALSE; }
if (!Fast486LoadSegmentInternal(State, FAST486_REG_GS, NewTss.Gs, FAST486_EXCEPTION_TS)) { return FALSE; } }
return TRUE;}
BOOLEANFASTCALLFast486CallGate(PFAST486_STATE State, PFAST486_CALL_GATE Gate, BOOLEAN Call){ BOOLEAN Valid; FAST486_GDT_ENTRY NewCodeSegment; BOOLEAN GateSize = (Gate->Type == FAST486_CALL_GATE_SIGNATURE); FAST486_TSS Tss; PFAST486_LEGACY_TSS LegacyTss = (PFAST486_LEGACY_TSS)&Tss; USHORT OldCs = State->SegmentRegs[FAST486_REG_CS].Selector; ULONG OldEip = State->InstPtr.Long; USHORT OldCpl = State->Cpl; USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector; ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long; ULONG ParamBuffer[32]; /* Maximum possible size - 32 DWORDs */ PULONG LongParams = (PULONG)ParamBuffer; PUSHORT ShortParams = (PUSHORT)ParamBuffer;
if (!Gate->Selector) { /* The code segment is NULL */ Fast486Exception(State, FAST486_EXCEPTION_GP); return FALSE; }
if (!Fast486ReadDescriptorEntry(State, Gate->Selector, &Valid, &NewCodeSegment)) { /* Exception occurred */ return FALSE; }
if (!Valid || (NewCodeSegment.Dpl > Fast486GetCurrentPrivLevel(State))) { /* Code segment invalid */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector); return FALSE; }
if (Call && Gate->ParamCount) { /* Read the parameters */ if (!Fast486ReadMemory(State, FAST486_REG_SS, OldEsp, FALSE, ParamBuffer, Gate->ParamCount * (GateSize ? sizeof(ULONG) : sizeof(USHORT)))) { /* Exception occurred */ return FALSE; } }
/* Check if the new code segment is more privileged */ if (NewCodeSegment.Dpl < OldCpl) { if (Call) { USHORT NewSs; ULONG NewEsp;
/* Read the TSS */ if (!Fast486ReadLinearMemory(State, State->TaskReg.Base, &Tss, State->TaskReg.Modern ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS), FALSE)) { /* Exception occurred */ return FALSE; }
/* Switch to the new privilege level */ State->Cpl = NewCodeSegment.Dpl;
/* Check the new (higher) privilege level */ switch (State->Cpl) { case 0: { if (State->TaskReg.Modern) { NewSs = Tss.Ss0; NewEsp = Tss.Esp0; } else { NewSs = LegacyTss->Ss0; NewEsp = LegacyTss->Sp0; }
break; }
case 1: { if (State->TaskReg.Modern) { NewSs = Tss.Ss1; NewEsp = Tss.Esp1; } else { NewSs = LegacyTss->Ss1; NewEsp = LegacyTss->Sp1; }
break; }
case 2: { if (State->TaskReg.Modern) { NewSs = Tss.Ss2; NewEsp = Tss.Esp2; } else { NewSs = LegacyTss->Ss2; NewEsp = LegacyTss->Sp2; }
break; }
default: { /* Should never reach here! */ ASSERT(FALSE); } }
if (!Fast486LoadSegment(State, FAST486_REG_SS, NewSs)) { /* Exception occurred */ return FALSE; }
State->GeneralRegs[FAST486_REG_ESP].Long = NewEsp; } else if (!NewCodeSegment.DirConf) { /* This is not allowed for jumps */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector); return FALSE; } }
/* Load new CS */ if (!Fast486LoadSegment(State, FAST486_REG_CS, Gate->Selector)) { /* An exception occurred during the jump */ return FALSE; }
/* Set the instruction pointer */ if (GateSize) State->InstPtr.Long = MAKELONG(Gate->Offset, Gate->OffsetHigh); else State->InstPtr.Long = Gate->Offset;
if (Call) { INT i;
/* Check if the new code segment is more privileged (again) */ if (NewCodeSegment.Dpl < OldCpl) { /* Push SS selector */ if (!Fast486StackPushInternal(State, GateSize, OldSs)) return FALSE;
/* Push stack pointer */ if (!Fast486StackPushInternal(State, GateSize, OldEsp)) return FALSE; }
/* Push the parameters in reverse order */ for (i = Gate->ParamCount - 1; i >= 0; i--) { if (!Fast486StackPushInternal(State, GateSize, GateSize ? LongParams[i] : ShortParams[i])) { /* Exception occurred */ return FALSE; } }
/* Push CS selector */ if (!Fast486StackPushInternal(State, GateSize, OldCs)) return FALSE;
/* Push the instruction pointer */ if (!Fast486StackPushInternal(State, GateSize, OldEip)) return FALSE; }
return TRUE;}
/* EOF */