WIP, untested

This commit is contained in:
Maschell 2023-10-06 16:51:09 +02:00
parent 98a137c91f
commit 0fbfd24198
8 changed files with 249 additions and 105 deletions

View File

@ -49,7 +49,7 @@ CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
endif
LIBS := -lwums -lwut -lfunctionpatcher
LIBS := -lwums -lwut -lfunctionpatcher -lmocha
#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level

View File

@ -7,20 +7,29 @@
static FSError processFSAShimInThread(FSAShimBuffer *shimBuffer) {
FSError res;
if (gThreadsRunning) {
auto upid = OSGetUPID();
if (!sLayerInfoForUPID.contains(upid)) {
DEBUG_FUNCTION_LINE_ERR("invalid UPID %d", upid);
OSFatal("Tried to start threads for invalid UPID.");
}
auto & layerInfo = sLayerInfoForUPID[upid];
if (layerInfo->threadsRunning) {
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
if (param == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapper");
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
}
param->upid = OSGetUPID();
param->api = FS_SHIM_API_FSA;
param->sync = FS_SHIM_TYPE_SYNC;
param->shim = shimBuffer;
if (OSGetCurrentThread() == gThreadData[OSGetCoreId()].thread) {
if (OSGetCurrentThread() == layerInfo->threadData[OSGetCoreId()].thread) {
res = processShimBufferForFSA(param);
//No need to clean "param", it has been already free'd in processFSAShimBuffer.
// No need to clean "param", it has been already free'd in processFSAShimBuffer.
} else {
auto message = (FSShimWrapperMessage *) malloc(sizeof(FSShimWrapperMessage));
if (message == nullptr) {
@ -31,7 +40,7 @@ static FSError processFSAShimInThread(FSAShimBuffer *shimBuffer) {
constexpr int32_t messageSize = sizeof(message->messages) / sizeof(message->messages[0]);
OSInitMessageQueue(&message->messageQueue, message->messages, messageSize);
if (!sendMessageToThread(message)) {
if (!sendMessageToThread(layerInfo, message)) {
DEBUG_FUNCTION_LINE_ERR("Failed to send message to thread");
OSFatal("ContentRedirectionModule: Failed send message to thread");
}

View File

@ -2,8 +2,10 @@
#include "FileUtils.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include <content_redirection/redirection.h>
#include <coreinit/core.h>
#include <coreinit/thread.h>
#include <mocha/mocha.h>
FSStatus processFSError(FSError fsError, FSClient *client, FSErrorFlag errorMask) {
auto result = fsError >= 0 ? static_cast<FSStatus>(fsError) : fsaDecodeFsaStatusToFsStatus(fsError);
@ -89,7 +91,15 @@ void handleAsyncRequestsCallback(IOSError err, void *context) {
bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBlock *block, FSErrorFlag errorMask, FSAsyncData *asyncData) {
bool res = false;
if (gThreadsRunning) {
auto upid = OSGetUPID();
if (!sLayerInfoForUPID.contains(upid)) {
DEBUG_FUNCTION_LINE_ERR("invalid UPID %d", upid);
OSFatal("Tried to start threads for invalid UPID.");
}
auto & layerInfo = sLayerInfoForUPID[upid];
if (layerInfo->threadsRunning) {
// we **don't** need to free this in this function.
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
if (param == nullptr) {
@ -97,6 +107,7 @@ bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBl
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
}
param->upid = OSGetUPID();
param->api = FS_SHIM_API_FS;
param->sync = FS_SHIM_TYPE_ASYNC;
param->shim = shimBuffer;
@ -111,7 +122,7 @@ bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBl
// Copy by value
param->asyncFS.errorMask = errorMask;
if (OSGetCurrentThread() == gThreadData[OSGetCoreId()].thread) {
if (OSGetCurrentThread() == layerInfo->threadData[OSGetCoreId()].thread) {
processShimBufferForFS(param);
// because we're doing this in sync, free(param) has already been called at this point.
res = true;
@ -122,7 +133,7 @@ bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBl
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapperMessage");
}
message->param = param;
res = sendMessageToThread(message);
res = sendMessageToThread(layerInfo, message);
// the other thread is call free for us, so we can return early!
}
} else {
@ -217,7 +228,6 @@ DECL_FUNCTION(FSStatus, FSOpenFileExAsync, FSClient *client, FSCmdBlock *block,
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) handle;
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
@ -555,28 +565,74 @@ DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, c
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
}
function_replacement_data_t fs_file_function_replacements[] = {
REPLACE_FUNCTION(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync),
REPLACE_FUNCTION(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync),
REPLACE_FUNCTION(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync),
REPLACE_FUNCTION(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync),
REPLACE_FUNCTION_VIA_ADDRESS(FSReadFileGeneric, 0x3201C400 + 0x4ecc0, 0x101C400 + 0x4ecc0),
REPLACE_FUNCTION(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync),
REPLACE_FUNCTION(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync),
REPLACE_FUNCTION(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync),
REPLACE_FUNCTION_VIA_ADDRESS(FSWriteFileGeneric, 0x3201C400 + 0x4eec0, 0x101C400 + 0x4eec0),
REPLACE_FUNCTION(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync),
REPLACE_FUNCTION(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync),
REPLACE_FUNCTION(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync),
REPLACE_FUNCTION(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync),
REPLACE_FUNCTION(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync),
DECL_FUNCTION(void, __PPCExit, uint32_t u1) {
auto UPID = OSGetUPID();
if (UPID != 2 && UPID != 15 && sLayerInfoForUPID.contains(UPID)) {
DEBUG_FUNCTION_LINE_ERR("Clear layer for UPID %d", UPID);
clearFSLayer(sLayerInfoForUPID[UPID]);
stopFSIOThreads();
}
real___PPCExit(u1);
}
REPLACE_FUNCTION(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync),
REPLACE_FUNCTION(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync),
REPLACE_FUNCTION(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync),
REPLACE_FUNCTION(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync),
REPLACE_FUNCTION(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync),
REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync),
MochaUtilsStatus MountWrapper(const char *mount, const char *dev, const char *mountTo) {
auto res = Mocha_MountFS(mount, dev, mountTo);
if (res == MOCHA_RESULT_ALREADY_EXISTS) {
res = Mocha_MountFS(mount, nullptr, mountTo);
}
if (res == MOCHA_RESULT_SUCCESS) {
std::string mountPath = std::string(mount) + ":/";
DEBUG_FUNCTION_LINE_VERBOSE("Mounted %s", mountPath.c_str());
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to mount %s: %s [%d]", mount, Mocha_GetStatusStr(res), res);
}
return res;
}
extern ContentRedirectionApiErrorType CRAddFSLayerEx(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType, uint32_t upid);
DECL_FUNCTION(void, START_HOOK) {
real_START_HOOK();
auto UPID = OSGetUPID();
if (UPID != 2 && UPID != 15 && sLayerInfoForUPID.contains(UPID)) {
DEBUG_FUNCTION_LINE_ERR("Clear layer for UPID %d", UPID);
clearFSLayer(sLayerInfoForUPID[UPID]);
DEBUG_FUNCTION_LINE_ERR("Start threads");
startFSIOThreads();
}
if (UPID == 8) {
CRLayerHandle handle;
int test = (int) 2;
Mocha_MountFS("storage_mlc", nullptr, "/vol/storage_mlc01");
CRAddFSLayerEx(&handle, "browser_test", "storage_mlc:/usr/tmp", FS_LAYER_TYPE_CONTENT_MERGE, UPID);
}
}
function_replacement_data_t fs_file_function_replacements[] = {
REPLACE_FUNCTION_FOR_PROCESS(__PPCExit, LIBRARY_COREINIT, __PPCExit, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(FSReadFileGeneric, 0x3201C400 + 0x4ecc0, 0x101C400 + 0x4ecc0, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(FSWriteFileGeneric, 0x3201C400 + 0x4eec0, 0x101C400 + 0x4eec0, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(START_HOOK, 0x3201C400 + 0x3edc0, 0x101C400 + 0x3edc0, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync, FP_TARGET_PROCESS_ALL),
REPLACE_FUNCTION_FOR_PROCESS(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync, FP_TARGET_PROCESS_ALL),
};
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);

View File

@ -239,7 +239,7 @@ FSWrapperMergeDirsWithParent::~FSWrapperMergeDirsWithParent() {
if (clientHandle) {
FSError res;
if ((res = FSADelClient(clientHandle)) != FS_ERROR_OK) {
DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res);
DEBUG_FUNCTION_LINE_ERR("FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res);
}
clientHandle = 0;
}

View File

@ -11,23 +11,17 @@
#include <map>
#include <unistd.h>
std::mutex workingDirMutex;
std::map<FSAClientHandle, std::string> workingDirs;
std::mutex fsLayerMutex;
std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
std::string getFullPathGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map<FSAClientHandle, std::string> &map) {
std::lock_guard<std::mutex> workingDirLock(mutex);
std::string getFullPathGeneric(std::shared_ptr<LayerInfo> &layerInfo, FSAClientHandle client, const char *path) {
std::lock_guard<std::mutex> workingDirLock(layerInfo->mutex);
std::string res;
if (path[0] != '/' && path[0] != '\\') {
if (map.count(client) == 0) {
if (layerInfo->workingDirs.count(client) == 0) {
DEBUG_FUNCTION_LINE_WARN("No working dir found for client %08X, fallback to \"/\"", client);
workingDirs[client] = "/";
layerInfo->workingDirs[client] = "/";
}
res = string_format("%s%s", map.at(client).c_str(), path);
res = string_format("%s%s", layerInfo->workingDirs.at(client).c_str(), path);
} else {
res = path;
}
@ -54,27 +48,33 @@ void setWorkingDirGeneric(FSAClientHandle client, const char *path, std::mutex &
}
std::string getFullPath(FSAClientHandle pClient, const char *path) {
return getFullPathGeneric(pClient, path, workingDirMutex, workingDirs);
std::string getFullPath(std::shared_ptr<LayerInfo> &layerInfo, FSAClientHandle pClient, const char *path) {
return getFullPathGeneric(layerInfo, pClient, path);
}
void setWorkingDir(FSAClientHandle client, const char *path) {
setWorkingDirGeneric(client, path, workingDirMutex, workingDirs);
void setWorkingDir(std::shared_ptr<LayerInfo> &layerInfo, FSAClientHandle client, const char *path) {
setWorkingDirGeneric(client, path, layerInfo->workingDirMutex, layerInfo->workingDirs);
}
void clearFSLayer() {
void clearFSLayer(std::shared_ptr<LayerInfo> &layerInfo) {
{
std::lock_guard<std::mutex> workingDirLock(workingDirMutex);
workingDirs.clear();
std::lock_guard<std::mutex> workingDirLock(layerInfo->workingDirMutex);
layerInfo->workingDirs.clear();
}
{
std::lock_guard<std::mutex> layerLock(fsLayerMutex);
fsLayers.clear();
std::lock_guard<std::mutex> layerLock(layerInfo->mutex);
layerInfo->layers.clear();
}
}
bool sendMessageToThread(FSShimWrapperMessage *param) {
auto *curThread = &gThreadData[OSGetCoreId()];
void clearFSLayers() {
for (auto &[upid, layerInfo] : sLayerInfoForUPID) {
clearFSLayer(layerInfo);
}
}
bool sendMessageToThread(std::shared_ptr<LayerInfo> &layerInfo, FSShimWrapperMessage *param) {
auto *curThread = &layerInfo->threadData[OSGetCoreId()];
if (curThread->setup) {
OSMessage send;
send.message = param;
@ -92,12 +92,20 @@ bool sendMessageToThread(FSShimWrapperMessage *param) {
return false;
}
std::map<uint32_t, std::shared_ptr<LayerInfo>> sLayerInfoForUPID;
FSError doForLayer(FSShimWrapper *param) {
std::lock_guard<std::mutex> lock(fsLayerMutex);
if (!fsLayers.empty()) {
uint32_t startIndex = fsLayers.size();
for (uint32_t i = fsLayers.size(); i > 0; i--) {
if ((uint32_t) fsLayers[i - 1]->getLayerId() == param->shim->clientHandle) {
if (!sLayerInfoForUPID.contains(param->upid)) {
DEBUG_FUNCTION_LINE_ERR("INVALID UPID IN SHIMWRAPPER: %d", param->upid);
OSFatal("Invalid UPID");
}
auto &layerInfo = sLayerInfoForUPID[param->upid];
std::lock_guard<std::mutex> lock(layerInfo->mutex);
if (!layerInfo->layers.empty()) {
uint32_t startIndex = layerInfo->layers.size();
for (uint32_t i = layerInfo->layers.size(); i > 0; i--) {
if ((uint32_t) layerInfo->layers[i - 1]->getLayerId() == param->shim->clientHandle) {
startIndex = i - 1;
break;
}
@ -105,7 +113,7 @@ FSError doForLayer(FSShimWrapper *param) {
if (startIndex > 0) {
for (uint32_t i = startIndex; i > 0; i--) {
auto &layer = fsLayers[i - 1];
auto &layer = layerInfo->layers[i - 1];
if (!layer->isActive()) {
continue;
}
@ -116,7 +124,7 @@ FSError doForLayer(FSShimWrapper *param) {
switch (command) {
case FSA_COMMAND_OPEN_DIR: {
auto *request = &param->shim->request.openDir;
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
DEBUG_FUNCTION_LINE_VERBOSE("[%s] OpenDir: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
@ -154,14 +162,14 @@ FSError doForLayer(FSShimWrapper *param) {
}
case FSA_COMMAND_MAKE_DIR: {
auto *request = &param->shim->request.makeDir;
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
DEBUG_FUNCTION_LINE_VERBOSE("[%s] MakeDir: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
layerResult = layer->FSMakeDirWrapper(fullPath.c_str());
break;
}
case FSA_COMMAND_OPEN_FILE: {
auto *request = &param->shim->request.openFile;
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *handlePtr = (FSFileHandle *) hackyBuffer[1];
@ -185,7 +193,7 @@ FSError doForLayer(FSShimWrapper *param) {
case FSA_COMMAND_GET_INFO_BY_QUERY: {
auto *request = &param->shim->request.getInfoByQuery;
if (request->type == FSA_QUERY_INFO_STAT) {
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
DEBUG_FUNCTION_LINE_VERBOSE("[%s] GetStat: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
@ -258,15 +266,15 @@ FSError doForLayer(FSShimWrapper *param) {
}
case FSA_COMMAND_REMOVE: {
auto *request = &param->shim->request.remove;
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Remove: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
layerResult = layer->FSRemoveWrapper(fullPath.c_str());
break;
}
case FSA_COMMAND_RENAME: {
auto *request = &param->shim->request.rename;
auto fullOldPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->oldPath);
auto fullNewPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->newPath);
auto fullOldPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->oldPath);
auto fullNewPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->newPath);
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Rename: %s -> %s (full path: %s -> %s)", layer->getName().c_str(), request->oldPath, request->newPath, fullOldPath.c_str(), fullNewPath.c_str());
layerResult = layer->FSRenameWrapper(fullOldPath.c_str(), fullNewPath.c_str());
break;
@ -280,7 +288,7 @@ FSError doForLayer(FSShimWrapper *param) {
case FSA_COMMAND_CHANGE_DIR: {
auto *request = &param->shim->request.changeDir;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] ChangeDir: %s", layer->getName().c_str(), request->path);
setWorkingDir((FSAClientHandle) param->shim->clientHandle, request->path);
setWorkingDir(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
// We still want to call the original function.
layerResult = FS_ERROR_FORCE_PARENT_LAYER;
break;
@ -458,9 +466,6 @@ int64_t writeFromBuffer(int32_t handle, const void *buffer, size_t size, size_t
return totalSize;
}
FSIOThreadData gThreadData[3];
bool gThreadsRunning = false;
static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv) {
auto *magic = ((FSIOThreadData *) argv);
@ -512,10 +517,24 @@ static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv)
void startFSIOThreads() {
int32_t threadAttributes[] = {OS_THREAD_ATTRIB_AFFINITY_CPU0, OS_THREAD_ATTRIB_AFFINITY_CPU1, OS_THREAD_ATTRIB_AFFINITY_CPU2};
auto stackSize = 16 * 1024;
auto upid = OSGetUPID();
if (!sLayerInfoForUPID.contains(upid)) {
DEBUG_FUNCTION_LINE_ERR("Tried to start threads for invalid UPID %d", upid);
OSFatal("Tried to start threads for invalid UPID.");
}
auto &layerInfo = sLayerInfoForUPID[upid];
if (layerInfo->threadsRunning) {
return;
}
int coreId = 0;
for (int core : threadAttributes) {
auto *threadData = &gThreadData[coreId];
if (upid != 2 && upid != 15 && core == OS_THREAD_ATTRIB_AFFINITY_CPU2) {
DEBUG_FUNCTION_LINE_ERR("Skip core 2 for non-game UPID %d", upid);
continue;
}
auto *threadData = &layerInfo->threadData[coreId];
memset(threadData, 0, sizeof(*threadData));
threadData->setup = false;
threadData->thread = (OSThread *) memalign(8, sizeof(OSThread));
@ -549,16 +568,24 @@ void startFSIOThreads() {
coreId++;
}
gThreadsRunning = true;
layerInfo->threadsRunning = true;
OSMemoryBarrier();
}
void stopFSIOThreads() {
if (!gThreadsRunning) {
auto upid = OSGetUPID();
if (!sLayerInfoForUPID.contains(upid)) {
DEBUG_FUNCTION_LINE_ERR("Tried to start threads for invalid UPID %d", upid);
OSFatal("Tried to start threads for invalid UPID.");
}
auto &layerInfo = sLayerInfoForUPID[upid];
if (!layerInfo->threadsRunning) {
return;
}
for (auto &gThread : gThreadData) {
auto *thread = &gThread;
for (auto &curThread : layerInfo->threadData) {
auto *thread = &curThread;
if (!thread->setup) {
continue;
}
@ -581,5 +608,5 @@ void stopFSIOThreads() {
}
}
gThreadsRunning = false;
layerInfo->threadsRunning = false;
}

View File

@ -6,6 +6,7 @@
#include <coreinit/filesystem.h>
#include <coreinit/filesystem_fsa.h>
#include <functional>
#include <map>
#include <mutex>
#include <romfs_dev.h>
#include <string>
@ -42,6 +43,7 @@ struct FSShimWrapper {
AsyncParamFS asyncFS;
FSShimSyncType sync;
FSShimApiType api;
uint32_t upid;
};
struct FSShimWrapperMessage {
@ -54,10 +56,16 @@ struct FSShimWrapperMessage {
#define FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND 0x42424242
#define FS_IO_QUEUE_SYNC_RESULT 0x43434343
extern bool gThreadsRunning;
extern FSIOThreadData gThreadData[3];
extern std::mutex fsLayerMutex;
extern std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
struct LayerInfo {
std::mutex mutex{};
std::vector<std::unique_ptr<IFSWrapper>> layers{};
std::mutex workingDirMutex{};
std::map<FSAClientHandle, std::string> workingDirs{};
FSIOThreadData threadData[3]{};
bool threadsRunning{};
};
extern std::map<uint32_t, std::shared_ptr<LayerInfo>> sLayerInfoForUPID;
#define fsaShimPrepareRequestReadFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, uint8_t * buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAReadFlag readFlags))(0x101C400 + 0x436cc))
#define fsaShimPrepareRequestWriteFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAWriteFlag writeFlags))(0x101C400 + 0x437f4))
@ -87,9 +95,11 @@ extern std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
extern "C" FSError __FSAShimDecodeIosErrorToFsaStatus(IOSHandle handle, IOSError err);
bool sendMessageToThread(FSShimWrapperMessage *param);
bool sendMessageToThread(std::shared_ptr<LayerInfo> &layerInfo, FSShimWrapperMessage *param);
void clearFSLayer();
void clearFSLayer(std::shared_ptr<LayerInfo> &layerInfo);
void clearFSLayers();
FSError doForLayer(FSShimWrapper *param);

View File

@ -16,12 +16,12 @@ struct AOCTitle {
WUT_CHECK_SIZE(AOCTitle, 0x68);
bool getAOCPath(std::string &outStr) {
int32_t (*AOC_Initialize)() = nullptr;
int32_t (*AOC_Finalize)() = nullptr;
int32_t (*AOC_ListTitle)(uint32_t * titleCountOut, AOCTitle * titleList, uint32_t maxCount, void *workBuffer, uint32_t workBufferSize) = nullptr;
int32_t (*AOC_OpenTitle)(char *pathOut, AOCTitle *aocTitleInfo, void *workBuffer, uint32_t workBufferSize) = nullptr;
int32_t (*AOC_CalculateWorkBufferSize)(uint32_t count) = nullptr;
int32_t (*AOC_CloseTitle)(AOCTitle * aocTitleInfo) = nullptr;
int32_t (*AOC_Initialize)() = nullptr;
int32_t (*AOC_Finalize)() = nullptr;
int32_t (*AOC_ListTitle)(uint32_t *titleCountOut, AOCTitle *titleList, uint32_t maxCount, void *workBuffer, uint32_t workBufferSize) = nullptr;
int32_t (*AOC_OpenTitle)(char *pathOut, AOCTitle *aocTitleInfo, void *workBuffer, uint32_t workBufferSize) = nullptr;
int32_t (*AOC_CalculateWorkBufferSize)(uint32_t count) = nullptr;
int32_t (*AOC_CloseTitle)(AOCTitle *aocTitleInfo) = nullptr;
AOCTitle title{};
char aocPath[256];
@ -88,7 +88,7 @@ end:
return result;
}
ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) {
ContentRedirectionApiErrorType CRAddFSLayerEx(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType, uint32_t upid) {
if (!handle || layerName == nullptr || replacementDir == nullptr) {
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
@ -121,28 +121,23 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l
}
if (ptr) {
DEBUG_FUNCTION_LINE_VERBOSE("Added new layer (%s). Replacement dir: %s Type:%d", layerName, replacementDir, layerType);
std::lock_guard<std::mutex> lock(fsLayerMutex);
auto &layerInfo = sLayerInfoForUPID[upid];
std::lock_guard<std::mutex> lock(layerInfo->mutex);
*handle = (CRLayerHandle) ptr->getHandle();
fsLayers.push_back(std::move(ptr));
layerInfo->layers.push_back(std::move(ptr));
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory");
return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY;
}
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
if (!remove_locked_first_if(fsLayerMutex, fsLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) {
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
}
return CONTENT_REDIRECTION_API_ERROR_NONE;
ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) {
return CRAddFSLayerEx(handle, layerName, replacementDir, layerType, 2);
}
ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
std::lock_guard<std::mutex> lock(fsLayerMutex);
for (auto &cur : fsLayers) {
if ((CRLayerHandle) cur->getHandle() == handle) {
cur->setActive(active);
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
for (auto &[key, layerInfo] : sLayerInfoForUPID) {
if (remove_locked_first_if(layerInfo->mutex, layerInfo->layers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) {
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
}
@ -151,11 +146,27 @@ ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
}
ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
for (auto &[key, layerInfo] : sLayerInfoForUPID) {
std::lock_guard<std::mutex> lock(layerInfo->mutex);
for (auto &cur : layerInfo->layers) {
if ((CRLayerHandle) cur->getHandle() == handle) {
cur->setActive(active);
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
}
}
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
}
ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersion) {
if (outVersion == nullptr) {
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
*outVersion = 1;
*outVersion = 2;
return CONTENT_REDIRECTION_API_ERROR_NONE;
}
@ -169,6 +180,7 @@ int CRRemoveDevice(const char *name) {
WUMS_EXPORT_FUNCTION(CRGetVersion);
WUMS_EXPORT_FUNCTION(CRAddFSLayer);
WUMS_EXPORT_FUNCTION(CRAddFSLayerEx);
WUMS_EXPORT_FUNCTION(CRRemoveFSLayer);
WUMS_EXPORT_FUNCTION(CRSetActive);
WUMS_EXPORT_FUNCTION(CRAddDevice);

View File

@ -3,7 +3,9 @@
#include "FileUtils.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include "utils/utils.h"
#include "version.h"
#include <mocha/mocha.h>
#include <wums.h>
WUMS_MODULE_EXPORT_NAME("homebrew_content_redirection");
@ -13,7 +15,14 @@ WUMS_DEPENDS_ON(homebrew_functionpatcher);
#define VERSION "v0.2.5"
DECL_FUNCTION(void, OSCancelThread, OSThread *thread) {
if (thread == gThreadData[0].thread || thread == gThreadData[1].thread || thread == gThreadData[2].thread) {
auto upid = OSGetUPID();
if (!sLayerInfoForUPID.contains(upid)) {
DEBUG_FUNCTION_LINE_ERR("invalid UPID %d", upid);
OSFatal("Invalid UPID.");
}
auto &layerInfo = sLayerInfoForUPID[upid];
if (thread == layerInfo->threadData[0].thread || thread == layerInfo->threadData[1].thread || thread == layerInfo->threadData[2].thread) {
DEBUG_FUNCTION_LINE_INFO("Prevent calling OSCancelThread for ContentRedirection IO Threads");
return;
}
@ -29,6 +38,11 @@ WUMS_INITIALIZE() {
OSFatal("homebrew_content_redirection: FunctionPatcher_InitLibrary failed");
}
int mochaInitResult;
if ((mochaInitResult = Mocha_InitLibrary()) != MOCHA_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Mocha_InitLibrary() failed %d", mochaInitResult);
}
bool wasPatched;
for (uint32_t i = 0; i < fs_file_function_replacements_size; i++) {
wasPatched = false;
@ -46,6 +60,19 @@ WUMS_INITIALIZE() {
if (FunctionPatcher_AddFunctionPatch(&OSCancelThreadReplacement, nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
OSFatal("homebrew_content_redirection: Failed to patch OSCancelThreadReplacement");
}
// Give UPID 2 (Wii U Menu) and UPID 15 the same layer
auto layerInfoGameMenu = make_shared_nothrow<LayerInfo>();
sLayerInfoForUPID[2] = layerInfoGameMenu;
sLayerInfoForUPID[15] = layerInfoGameMenu;
// Fill in for all other UPIDs
for (int i = 0; i < 16; i++) {
if (i == 2 || i == 15) {
continue;
}
sLayerInfoForUPID[i] = make_shared_nothrow<LayerInfo>();
}
DEBUG_FUNCTION_LINE("Patch functions finished");
deinitLogging();
}
@ -57,7 +84,10 @@ WUMS_APPLICATION_STARTS() {
}
WUMS_APPLICATION_ENDS() {
clearFSLayer();
if (sLayerInfoForUPID.contains(2)) {
DEBUG_FUNCTION_LINE_ERR("Clear layer for UPID %d", 2);
clearFSLayer(sLayerInfoForUPID[2]);
}
stopFSIOThreads();