| 944 | void BTCpu64NotifyReadFile(HANDLE Handle, void* Address, SIZE_T Size, BOOL After, NTSTATUS Status) {} |
| 945 | |
| 946 | NTSTATUS ThreadInit() { |
| 947 | std::scoped_lock Lock(ThreadCreationMutex); |
| 948 | FEX::Windows::InitCRTThread(); |
| 949 | static constexpr size_t EmulatorStackSize = 0x40000; |
| 950 | const uint64_t EmulatorStack = reinterpret_cast<uint64_t>(::VirtualAlloc(nullptr, EmulatorStackSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); |
| 951 | GetCPUArea().EmulatorStackLimit() = EmulatorStack; |
| 952 | GetCPUArea().EmulatorStackBase() = EmulatorStack + EmulatorStackSize; |
| 953 | |
| 954 | const auto CPUArea = GetCPUArea(); |
| 955 | |
| 956 | auto* Thread = CTX->CreateThread(0, 0); |
| 957 | |
| 958 | // Default segment setup. |
| 959 | auto Frame = Thread->CurrentFrame; |
| 960 | auto NewSegments = new FEXCore::Core::CPUState::gdt_segment[32]; |
| 961 | |
| 962 | // Setup initial code-segment GDT |
| 963 | auto& GDT = NewSegments[FEXCore::Core::CPUState::DEFAULT_USER_CS]; |
| 964 | FEXCore::Core::CPUState::SetGDTBase(&GDT, 0); |
| 965 | FEXCore::Core::CPUState::SetGDTLimit(&GDT, 0xF'FFFFU); |
| 966 | GDT.L = 1; // L = Long Mode = 64-bit |
| 967 | GDT.D = 0; // D = Default Operand SIze = Reserved |
| 968 | |
| 969 | Frame->State.segment_arrays[FEXCore::Core::CPUState::SEGMENT_ARRAY_INDEX_GDT] = &NewSegments[0]; |
| 970 | // TODO: LDTs are currently unsupported, mirror them to GDT. |
| 971 | Frame->State.segment_arrays[FEXCore::Core::CPUState::SEGMENT_ARRAY_INDEX_LDT] = &NewSegments[0]; |
| 972 | |
| 973 | Frame->State.cs_idx = FEXCore::Core::CPUState::DEFAULT_USER_CS << 3; |
| 974 | Frame->State.cs_cached = FEXCore::Core::CPUState::CalculateGDTBase(GDT); |
| 975 | |
| 976 | FEX::Windows::CallRetStack::InitializeThread(Thread); |
| 977 | Thread->CurrentFrame->Pointers.Common.ExitFunctionEC = reinterpret_cast<uintptr_t>(&ExitFunctionEC); |
| 978 | CPUArea.StateFrame() = Thread->CurrentFrame; |
| 979 | |
| 980 | uint64_t EnterEC = Thread->CurrentFrame->Pointers.Common.DispatcherLoopTopEnterEC; |
| 981 | CPUArea.DispatcherLoopTopEnterEC() = EnterEC; |
| 982 | |
| 983 | uint64_t EnterECFillSRA = Thread->CurrentFrame->Pointers.Common.DispatcherLoopTopEnterECFillSRA; |
| 984 | CPUArea.DispatcherLoopTopEnterECFillSRA() = EnterECFillSRA; |
| 985 | |
| 986 | CPUArea.ContextAmd64() = {.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT, |
| 987 | .AMD64_SegCs = (FEXCore::Core::CPUState::DEFAULT_USER_CS << 3) | 3, |
| 988 | .AMD64_SegDs = 0x2b, |
| 989 | .AMD64_SegEs = 0x2b, |
| 990 | .AMD64_SegFs = 0x53, |
| 991 | .AMD64_SegGs = 0x2b, |
| 992 | .AMD64_SegSs = 0x2b, |
| 993 | .AMD64_EFlags = 0x202, |
| 994 | .AMD64_MxCsr = 0x1f80, |
| 995 | .AMD64_MxCsr_copy = 0x1f80, |
| 996 | .AMD64_ControlWord = 0x27f}; |
| 997 | Exception::LoadStateFromECContext(Thread, CPUArea.ContextAmd64().AMD64_Context); |
| 998 | |
| 999 | { |
| 1000 | auto ThreadTID = GetCurrentThreadId(); |
| 1001 | Threads.emplace(ThreadTID, Thread); |
| 1002 | if (StatAllocHandler) { |
| 1003 | Thread->ThreadStats = StatAllocHandler->AllocateSlot(ThreadTID); |
nothing calls this directly
no test coverage detected