diff --git a/src/core/kernel/exports/EmuKrnlPs.cpp b/src/core/kernel/exports/EmuKrnlPs.cpp index 674c75a21..124e4e4b9 100644 --- a/src/core/kernel/exports/EmuKrnlPs.cpp +++ b/src/core/kernel/exports/EmuKrnlPs.cpp @@ -264,6 +264,10 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx }*/ HANDLE handle = reinterpret_cast(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, reinterpret_cast(&dwThreadId))); + if (handle == NULL) { + delete iPCSTProxyParam; + RETURN(xbox::status_insufficient_resources); + } *ThreadHandle = handle; if (ThreadId != NULL) *ThreadId = dwThreadId; @@ -378,6 +382,7 @@ XBSYSAPI EXPORTNUM(258) xbox::void_xt NTAPI xbox::PsTerminateSystemThread } }*/ + EmuKeFreePcr(); _endthreadex(ExitStatus); // ExitThread(ExitStatus); // CxbxKrnlTerminateThread(); diff --git a/src/core/kernel/support/EmuFS.cpp b/src/core/kernel/support/EmuFS.cpp index 8b1b9c339..a667b91ad 100644 --- a/src/core/kernel/support/EmuFS.cpp +++ b/src/core/kernel/support/EmuFS.cpp @@ -188,6 +188,39 @@ void EmuKeSetPcr(xbox::KPCR *Pcr) __writefsdword(TIB_ArbitraryDataSlot, (DWORD)Pcr); } +void EmuKeFreePcr() +{ + // NOTE: don't call KeGetPcr because that one creates a new pcr for the thread when __readfsdword returns nullptr, which we don't want + xbox::PKPCR Pcr = reinterpret_cast(__readfsdword(TIB_ArbitraryDataSlot)); + + if (Pcr) { + // tls can be nullptr + xbox::PVOID Dummy; + xbox::ulong_xt Size; + xbox::ntstatus_xt Status; + if (Pcr->NtTib.StackBase) { + // NOTE: the tls pointer was increased by 12 bytes to enforce the 16 bytes alignment, so adjust it to reach the correct pointer + // that was allocated by xbox::NtAllocateVirtualMemory + Dummy = static_cast(Pcr->NtTib.StackBase) - 12; + Size = xbox::zero; + Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free tls + assert(Status == xbox::status_success); + } + Dummy = Pcr->Prcb->CurrentThread; + Size = xbox::zero; + Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free ethread + assert(Status == xbox::status_success); + Dummy = Pcr; + Size = xbox::zero; + Status = xbox::NtFreeVirtualMemory(&Dummy, &Size, XBOX_MEM_RELEASE); // free pcr + assert(Status == xbox::status_success); + __writefsdword(TIB_ArbitraryDataSlot, NULL); + } + else { + EmuLog(LOG_LEVEL::WARNING, "__readfsdword in EmuKeFreePcr returned nullptr: was this called from a non-xbox thread?"); + } +} + __declspec(naked) void EmuFS_RefreshKPCR() { // Backup all registers, call KeGetPcr and then restore all registers @@ -517,6 +550,8 @@ void EmuInitFS() void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData) { void *pNewTLS = nullptr; + xbox::PVOID base; + xbox::ulong_xt size; // Be aware that TLS might be absent (for example in homebrew "Wolf3d-xbox") if (pTLS != nullptr) { @@ -536,9 +571,12 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData) } /* + HACK: extra safety padding 0x100 */ - pNewTLS = (void*)xbox::ExAllocatePool(dwCopySize + dwZeroSize + 0x100 + 0xC); + base = xbox::zeroptr; + size = dwCopySize + dwZeroSize + 0x100 + 0xC; + xbox::NtAllocateVirtualMemory(&base, 0, &size, XBOX_MEM_RESERVE | XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE); + pNewTLS = (void*)base; xbox::RtlZeroMemory(pNewTLS, dwCopySize + dwZeroSize + 0x100 + 0xC); - /* Skip the first 12 bytes so that TLSData will be 16 byte aligned (addr returned by AllocateZeroed is 4K aligned) */ + /* Skip the first 12 bytes so that TLSData will be 16 byte aligned (addr returned by NtAllocateVirtualMemory is 4K aligned) */ pNewTLS = (uint8_t*)pNewTLS + 12; if (dwCopySize > 0) { @@ -583,7 +621,10 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData) } // Allocate the xbox KPCR structure - xbox::KPCR *NewPcr = (xbox::KPCR*)xbox::ExAllocatePool(sizeof(xbox::KPCR)); + base = xbox::zeroptr; + size = sizeof(xbox::KPCR); + xbox::NtAllocateVirtualMemory(&base, 0, &size, XBOX_MEM_RESERVE | XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE); + xbox::KPCR *NewPcr = (xbox::KPCR*)base; xbox::RtlZeroMemory(NewPcr, sizeof(xbox::KPCR)); xbox::NT_TIB *XbTib = &(NewPcr->NtTib); xbox::PKPRCB Prcb = &(NewPcr->PrcbData); @@ -630,7 +671,10 @@ void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData) // Initialize a fake PrcbData.CurrentThread { - xbox::ETHREAD *EThread = (xbox::ETHREAD*)xbox::ExAllocatePool(sizeof(xbox::ETHREAD)); // Clear, to prevent side-effects on random contents + base = xbox::zeroptr; + size = sizeof(xbox::ETHREAD); + xbox::NtAllocateVirtualMemory(&base, 0, &size, XBOX_MEM_RESERVE | XBOX_MEM_COMMIT, XBOX_PAGE_READWRITE); + xbox::ETHREAD *EThread = (xbox::ETHREAD*)base; // Clear, to prevent side-effects on random contents xbox::RtlZeroMemory(EThread, sizeof(xbox::ETHREAD)); EThread->Tcb.TlsData = pNewTLS; diff --git a/src/core/kernel/support/EmuFS.h b/src/core/kernel/support/EmuFS.h index 5f0053cf7..029b2c75d 100644 --- a/src/core/kernel/support/EmuFS.h +++ b/src/core/kernel/support/EmuFS.h @@ -34,6 +34,8 @@ extern void EmuInitFS(); // generate fs segment selector extern void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData); +// free resources allocated for the thread +void EmuKeFreePcr(); typedef struct {