/*++ Copyright (c) 1995-2000 Microsoft Corporation Module Name: cpumain.c Abstract: This module implements the public interface to the CPU. Author: 03-Jul-1995 BarryBo Revision History: --*/ #include #include #include #include #include #define _WX86CPUAPI_ #include "wx86nt.h" #include "wx86cpu.h" #include "cpuassrt.h" #include "config.h" #include "instr.h" #include "threadst.h" #include "cpunotif.h" #include "cpuregs.h" #include "entrypt.h" #include "compiler.h" #include "instr.h" #include "frag.h" #include "entrypt.h" #include "mrsw.h" #include "tc.h" #include "cpumain.h" #include "wx86.h" #include "atomic.h" #ifdef CODEGEN_PROFILE #include #endif #include "wow64t.h" #include ASSERTNAME; // // Identify the CPU type for the debugger extensions // WX86_CPUTYPE Wx86CpuType = Wx86CpuCpu; // // Per-process CpuNotify bits. These are different than the per-thread // bits. // DWORD ProcessCpuNotify; NTSTATUS MsCpuProcessInit( VOID ) /*++ Routine Description: Initialize the CPU. Must be called once at process initialization. Arguments: None Return Value: None --*/ { #if 0 DbgBreakPoint(); #endif // // Read all configuration data from the registry // GetConfigurationData(); MrswInitializeObject(&MrswEP); MrswInitializeObject(&MrswTC); MrswInitializeObject(&MrswIndirTable); if (!InitializeTranslationCache()) { return STATUS_UNSUCCESSFUL; } if (!initEPAlloc()) { #if DBG LOGPRINT((TRACELOG, "CpuProcessInit: Entry Point allocator initialization failed")); #endif return STATUS_UNSUCCESSFUL; } if (!initializeEntryPointModule()) { #if DBG LOGPRINT((TRACELOG, "CpuProcessInit: Entry Point module initialization failed")); #endif return STATUS_UNSUCCESSFUL; } #if 0 if (!(Wx86LockSynchMutexHandle = CreateMutex(NULL, FALSE, "Wx86LockSynchMutex"))) { #if DBG LOGPRINT((TRACELOG, "CpuProcessInit: Cannot create Wx86LockSynchMutex")); #endif return STATUS_UNSUCCESSFUL; } #endif RtlInitializeCriticalSection(&Wx86LockSynchCriticalSection); SynchObjectType = USECRITICALSECTION; #ifdef CODEGEN_PROFILE InitCodegenProfile(); #endif return STATUS_SUCCESS; } BOOL MsCpuProcessTerm( BOOL OFlyInit ) { #if 0 NtClose(Wx86LockSynchMutexHandle); termEPAlloc(); #endif return TRUE; } BOOL MsCpuThreadInit( VOID ) /*++ Routine Description: Initialize the CPU. Must be called once for each thread. Arguments: None. Return Value: TRUE if successful initialization, FALSE if init failed. --*/ { DWORD StackBase; PTEB32 Teb32 = WOW64_GET_TEB32(NtCurrentTeb()); DECLARE_CPU; if (!FragLibInit(cpu, Teb32->NtTib.StackBase)) { return FALSE; } // // Mark the callstack as valid // cpu->CSTimestamp = TranslationCacheTimestamp; // // Mark the TC as being unlocked // cpu->fTCUnlocked = TRUE; // // All done. // return TRUE; } VOID CpuResetToConsistentState( PEXCEPTION_POINTERS pExceptionPointers ) /*++ Routine Description: Called by WX86 when the exception filter around CpuSimulate() fires. Arguments: pExceptionPointers - state of the thread at the time the exception occurred. Return Value: None --*/ { DECLARE_CPU; if (!cpu->fTCUnlocked) { // // We must unlock the TC before continuing // MrswReaderExit(&MrswTC); cpu->fTCUnlocked = TRUE; // // Call the compiler to deduce where Eip should be pointing // based on the RISC exception record. It is called with // the Entrypoint write lock because it calls the compiler. // The compiler's global vars are usable only with EP write. // MrswWriterEnter(&MrswEP); GetEipFromException(cpu, pExceptionPointers); MrswWriterExit(&MrswEP); } Wow64TlsSetValue(WOW64_TLS_EXCEPTIONADDR, LongToPtr(cpu->eipReg.i4)); } VOID CpuPrepareToContinue( PEXCEPTION_POINTERS pExceptionPointers ) /*++ Routine Description: Called by WX86 prior to resuming execution on EXCEPTION_CONTINUE_EXECUTION Arguments: pExceptionPointers - alpha context with which execution will be resumed. Return Value: None --*/ { } BOOLEAN CpuMapNotify( PVOID DllBase, BOOLEAN Mapped ) /*++ Routine Description: Called by WX86 when an x86 DLL is loaded or unloaded. Arguments: DllBase -- address where x86 DLL was loaded. Mapped -- TRUE if x86 DLL was just mapped in, FALSE if DLL is just about to be unmapped. Return Value: TRUE on success, FALSE on failure. --*/ { if (Mapped) { NTSTATUS st; MEMORY_BASIC_INFORMATION mbi; ULONG Length; st = NtQueryVirtualMemory(NtCurrentProcess(), DllBase, MemoryBasicInformation, &mbi, sizeof(mbi), NULL); if (NT_SUCCESS(st)) { Length = (ULONG)mbi.RegionSize; } else { // Flush the whole translation cache DllBase = 0; Length = 0xffffffff; } CpuFlushInstructionCache(DllBase, Length); } return TRUE; } VOID CpuEnterIdle( BOOL OFly ) /*++ Routine Description: Called by WX86 when Wx86 ofly is going idle, or when Wx86 is out of memory and needs some pages. The CPU must free as many resources as possible. Arguments: OFly - TRUE if called from on-the-fly, FALSE if called due to out of memory. Return Value: None. --*/ { CpuFlushInstructionCache(0, 0xffffffff); } BOOL CpuIsProcessorFeaturePresent( DWORD ProcessorFeature ) /*++ Routine Description: Called by whkrnl32!whIsProcessorFeaturePresent(). The CPU gets to fill in its own feature set. Arguments: ProcessorFeature -- feature to query (see winnt.h PF_*) Return Value: TRUE if feature present, FALSE if not. --*/ { BOOL fRet; switch (ProcessorFeature) { case PF_FLOATING_POINT_PRECISION_ERRATA: case PF_COMPARE_EXCHANGE_DOUBLE: case PF_MMX_INSTRUCTIONS_AVAILABLE: fRet = FALSE; break; case PF_FLOATING_POINT_EMULATED: // // TRUE when winpxem.dll used to emulate floating-point with x86 // integer instructions. // fRet = fUseNPXEM; break; default: // // Look up the native feature set // fRet = ProxyIsProcessorFeaturePresent(ProcessorFeature); } return fRet; }