Merge pull request #2171 from ergo720/free_thread_resources

Free thread resources upon termination
This commit is contained in:
Luke Usher 2021-03-24 06:13:22 +00:00 committed by GitHub
commit 187f4a8162
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 4 deletions

View File

@ -264,6 +264,10 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
}*/
HANDLE handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL, KernelStackSize, PCSTProxy, iPCSTProxyParam, CREATE_SUSPENDED, reinterpret_cast<unsigned int*>(&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();

View File

@ -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<xbox::PKPCR>(__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<xbox::PBYTE>(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;

View File

@ -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
{