Use the default heap for threads, make sure to memset default heap allocations to 0 after using them

This commit is contained in:
Maschell 2023-03-26 15:53:56 +02:00
parent 6076c8726c
commit f2333e37dc
5 changed files with 65 additions and 9 deletions

View File

@ -1,4 +1,4 @@
FROM ghcr.io/wiiu-env/devkitppc:20221228 FROM ghcr.io/wiiu-env/devkitppc:20230326
COPY --from=ghcr.io/wiiu-env/libkernel:20220904 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libkernel:20220904 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230106 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230106 /artifacts $DEVKITPRO

View File

@ -16,8 +16,10 @@
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include "globals.h"
#include <coreinit/thread.h> #include <coreinit/thread.h>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <malloc.h> #include <malloc.h>
#include <unistd.h> #include <unistd.h>
@ -26,14 +28,15 @@ public:
typedef void (*Callback)(CThread *thread, void *arg); typedef void (*Callback)(CThread *thread, void *arg);
//! constructor //! constructor
explicit CThread(int32_t iAttr, int32_t iPriority = 16, int32_t iStackSize = 0x8000, CThread::Callback callback = nullptr, void *callbackArg = nullptr) explicit CThread(int32_t iAttr, int32_t iPriority = 16, int32_t stacksize = 0x8000, CThread::Callback callback = nullptr, void *callbackArg = nullptr)
: pThread(nullptr), pThreadStack(nullptr), pCallback(callback), pCallbackArg(callbackArg) { : pThread(nullptr), pThreadStack(nullptr), pCallback(callback), pCallbackArg(callbackArg) {
//! save attribute assignment //! save attribute assignment
iAttributes = iAttr; iAttributes = iAttr;
//! allocate the thread iStackSize = stacksize;
pThread = (OSThread *) memalign(8, 0x1000); //! allocate the thread on the default Cafe OS heap
//! allocate the stack pThread = (OSThread *) gMEMAllocFromDefaultHeapExForThreads(sizeof(OSThread), 0x10);
pThreadStack = (uint8_t *) memalign(0x20, iStackSize); //! allocate the stack on the default Cafe OS heap
pThreadStack = (uint8_t *) gMEMAllocFromDefaultHeapExForThreads(iStackSize, 0x20);
//! create the thread //! create the thread
if (pThread && pThreadStack) { if (pThread && pThreadStack) {
// clang-format off // clang-format off
@ -71,7 +74,9 @@ public:
//! Resume thread //! Resume thread
virtual void resumeThread() { virtual void resumeThread() {
if (!isThreadSuspended()) return; if (!isThreadSuspended()) return;
if (pThread) OSResumeThread(pThread); if (pThread) {
OSResumeThread(pThread);
}
} }
//! Set thread priority //! Set thread priority
@ -111,12 +116,16 @@ public:
} }
OSJoinThread(pThread, nullptr); OSJoinThread(pThread, nullptr);
} }
// Some games (e.g. Minecraft) expect the default heap to be empty.
// Make sure to clean up the memory after using it
//! free the thread stack buffer //! free the thread stack buffer
if (pThreadStack) { if (pThreadStack) {
free(pThreadStack); memset(pThreadStack, 0, iStackSize);
gMEMFreeToDefaultHeapForThreads(pThreadStack);
} }
if (pThread) { if (pThread) {
free(pThread); memset(pThread, 0, sizeof(OSThread));
gMEMFreeToDefaultHeapForThreads(pThread);
} }
pThread = nullptr; pThread = nullptr;
pThreadStack = nullptr; pThreadStack = nullptr;
@ -139,6 +148,7 @@ private:
return 0; return 0;
} }
uint32_t iStackSize;
int32_t iAttributes; int32_t iAttributes;
OSThread *pThread; OSThread *pThread;
uint8_t *pThreadStack; uint8_t *pThreadStack;

4
source/globals.c Normal file
View File

@ -0,0 +1,4 @@
#include "globals.h"
void *(*gMEMAllocFromDefaultHeapExForThreads)(uint32_t size, int align);
void (*gMEMFreeToDefaultHeapForThreads)(void *ptr);

5
source/globals.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern void *(*gMEMAllocFromDefaultHeapExForThreads)(uint32_t size, int align);
extern void (*gMEMFreeToDefaultHeapForThreads)(void *ptr);

View File

@ -1,4 +1,6 @@
#include "function_replacements.h" #include "function_replacements.h"
#include "globals.h"
#include "logger.h"
#include "memory_mapping.h" #include "memory_mapping.h"
#include "version.h" #include "version.h"
#include <coreinit/debug.h> #include <coreinit/debug.h>
@ -16,15 +18,45 @@ WUMS_MODULE_INIT_BEFORE_RELOCATION_DONE_HOOK();
WUMS_DEPENDS_ON(homebrew_kernel); WUMS_DEPENDS_ON(homebrew_kernel);
WUMS_DEPENDS_ON(homebrew_functionpatcher); WUMS_DEPENDS_ON(homebrew_functionpatcher);
#include <coreinit/dynload.h>
#include <coreinit/memdefaultheap.h>
// We can't use the functions from libfunctionpatcher. Defined in functionpatcher.def // We can't use the functions from libfunctionpatcher. Defined in functionpatcher.def
extern "C" FunctionPatcherStatus FPAddFunctionPatch(function_replacement_data_t *function_data, PatchedFunctionHandle *outHandle, bool *outHasBeenPatched); extern "C" FunctionPatcherStatus FPAddFunctionPatch(function_replacement_data_t *function_data, PatchedFunctionHandle *outHandle, bool *outHasBeenPatched);
void UpdateFunctionPointer() {
// We need the real MEMAllocFromDefaultHeapEx/MEMFreeToDefaultHeap function pointer to force-allocate memory on the default heap.
// Our custom heap doesn't work (yet) for threads and causes an app panic.
OSDynLoad_Module coreinitModule;
if (OSDynLoad_Acquire("coreinit", &coreinitModule) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to acquire coreinit.rpl");
OSFatal("FunctionPatcherModule: Failed to acquire coreinit.rpl");
}
/* Memory allocation functions */
uint32_t *allocPtr, *freePtr;
if (OSDynLoad_FindExport(coreinitModule, OS_DYNLOAD_EXPORT_DATA, "MEMAllocFromDefaultHeapEx", reinterpret_cast<void **>(&allocPtr)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("OSDynLoad_FindExport for MEMAllocFromDefaultHeapEx");
OSFatal("MemoryMappingModule: OSDynLoad_FindExport for MEMAllocFromDefaultHeapEx");
}
if (OSDynLoad_FindExport(coreinitModule, OS_DYNLOAD_EXPORT_DATA, "MEMFreeToDefaultHeap", reinterpret_cast<void **>(&freePtr)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("OSDynLoad_FindExport for MEMFreeToDefaultHeap");
OSFatal("MemoryMappingModule: OSDynLoad_FindExport for MEMFreeToDefaultHeap");
}
gMEMAllocFromDefaultHeapExForThreads = (void *(*) (uint32_t, int) ) * allocPtr;
gMEMFreeToDefaultHeapForThreads = (void (*)(void *)) * freePtr;
OSDynLoad_Release(coreinitModule);
}
WUMS_INITIALIZE(args) { WUMS_INITIALIZE(args) {
static uint8_t ucSetupRequired = 1; static uint8_t ucSetupRequired = 1;
if (!ucSetupRequired) { if (!ucSetupRequired) {
return; return;
} }
UpdateFunctionPointer();
ucSetupRequired = 0; ucSetupRequired = 0;
MemoryMapping_setupMemoryMapping(); MemoryMapping_setupMemoryMapping();
MemoryMapping_CreateHeaps(); MemoryMapping_CreateHeaps();
@ -45,6 +77,11 @@ WUMS_INITIALIZE(args) {
WUMS_APPLICATION_STARTS() { WUMS_APPLICATION_STARTS() {
OSReport("Running MemoryMappingModule " VERSION VERSION_EXTRA "\n"); OSReport("Running MemoryMappingModule " VERSION VERSION_EXTRA "\n");
// Now we can update the pointer with the "real" functions
gMEMAllocFromDefaultHeapExForThreads = MEMAllocFromDefaultHeapEx;
gMEMFreeToDefaultHeapForThreads = MEMFreeToDefaultHeap;
#ifdef DEBUG #ifdef DEBUG
initLogging(); initLogging();
#endif #endif