summaryrefslogtreecommitdiff
path: root/src/toBeSorted/nand_request_thread.cpp
diff options
context:
space:
mode:
authorrobojumper <robojumper@gmail.com>2025-02-28 14:01:46 +0100
committerrobojumper <robojumper@gmail.com>2025-02-28 14:01:46 +0100
commitc7d788117e399bdf7a4001f55f00d12499f128fe (patch)
tree913f2916e501614931a3c59be1c036665bae14c0 /src/toBeSorted/nand_request_thread.cpp
parentc2b2d9700c47c1eb4c6026fee14d1d9b247f8fe8 (diff)
NandRequestThread
Diffstat (limited to 'src/toBeSorted/nand_request_thread.cpp')
-rw-r--r--src/toBeSorted/nand_request_thread.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/toBeSorted/nand_request_thread.cpp b/src/toBeSorted/nand_request_thread.cpp
new file mode 100644
index 00000000..ff1ace2f
--- /dev/null
+++ b/src/toBeSorted/nand_request_thread.cpp
@@ -0,0 +1,321 @@
+#include "toBeSorted/nand_request_thread.h"
+
+#include "common.h"
+#include "egg/core/eggAssertHeap.h" // IWYU pragma: export
+#include "egg/core/eggThread.h"
+#include "m/m_heap.h"
+#include "rvl/NAND/NANDCheck.h"
+#include "rvl/NAND/NANDCore.h"
+#include "rvl/NAND/nand.h"
+#include "rvl/OS/OSMessage.h"
+#include "rvl/OS/OSMutex.h"
+#include "rvl/OS/OSThread.h"
+
+#include <cstring>
+
+extern "C" void fn_802F2920(OSThread *, size_t);
+
+NandRequestThread::NandRequestThread(
+ int priority, EGG::Heap *commandHeap, void *bufFromGameHeap, size_t bufSize, void *mThreadArg, EGG::Heap *heap
+)
+ : EGG::Thread(0x4000, 0, priority, heap), mMessageBuffer(nullptr) {
+ // TODO suffers from TList ctor
+ sInstance = this;
+
+ mpCommandHeap = commandHeap;
+ mBufFromGameHeap = bufFromGameHeap;
+ mBufSize = bufSize;
+
+ setThreadCurrentHeap(mHeap::g_assertHeap);
+ fn_802F2920(mOSThread, bufSize);
+ OSInitMessageQueue(&mMessageQueue, &mMessageBuffer, 1);
+ OSInitMutex(&mMutex);
+ OSResumeThread(mOSThread);
+}
+
+NandRequestThread::~NandRequestThread() {
+ sInstance = nullptr;
+}
+
+void *NandRequestThread::run() {
+ NandRequest *req;
+ while (waitForMessage()) {
+ while (mRequestList.mCount != 0) {
+ req = dequeueRequest();
+ req->execute();
+ req->bHandled = true;
+ }
+ }
+ return nullptr;
+}
+
+NandRequestCheck *NandRequestThread::checkRequest(u32 neededBlocks, u32 neededFiles) {
+ NandRequestCheck *req = new NandRequestCheck(neededBlocks, neededFiles);
+ if (req != nullptr) {
+ enqueueRequest(req);
+ }
+ return req;
+}
+
+NandRequestCreate *NandRequestThread::createRequest(const char *filePath, u8 perm, u8 attr) {
+ NandRequestCreate *req = new NandRequestCreate(filePath, perm, attr);
+ if (req != nullptr) {
+ enqueueRequest(req);
+ }
+ return req;
+}
+
+NandRequestWrite *NandRequestThread::writeRequest(const char *filePath, void *data, size_t dataSize) {
+ NandRequestWrite *req = new NandRequestWrite(filePath, data, dataSize);
+ if (req != nullptr) {
+ enqueueRequest(req);
+ }
+ return req;
+}
+
+bool NandRequestThread::waitForMessage() {
+ return OSReceiveMessage(&mMessageQueue, nullptr, OS_MSG_PERSISTENT);
+}
+
+void NandRequestThread::sendMessage() {
+ OSSendMessage(&mMessageQueue, nullptr, 0);
+}
+
+void NandRequestThread::enqueueRequest(NandRequest *request) {
+ mRequestList.insert(request);
+ sendMessage();
+}
+
+NandRequest *NandRequestThread::dequeueRequest() {
+ // TODO TList
+ NandRequest *req = mRequestList.GetFirst();
+
+ OSLockMutex(&mMutex);
+ mRequestList.RemoveFirst();
+ OSUnlockMutex(&mMutex);
+
+ sendMessage();
+ return req;
+}
+
+NandRequestThread *NandRequestThread::create(
+ int priority, EGG::Heap *commandHeap, void *bufFromGameHeap, size_t bufSize, void *mThreadArg, EGG::Heap *heap
+) {
+ return new (heap, 0x04) NandRequestThread(priority, commandHeap, bufFromGameHeap, bufSize, mThreadArg, heap);
+}
+
+void *NandRequest::operator new(size_t size) {
+ return NandRequestThread::sInstance->mpCommandHeap->alloc(size, -4);
+}
+
+void NandRequest::free(NandRequest *ptr) {
+ return NandRequestThread::sInstance->mpCommandHeap->free(ptr);
+}
+
+NANDResult NandRequest::getStatus() const {
+ return mStatus;
+}
+
+NandRequestCheck::NandRequestCheck(u32 neededBlocks, u32 neededFiles) {
+ mResult = 0;
+ mNeededBlocks = neededBlocks;
+ mNeededFiles = neededFiles;
+}
+
+bool NandRequestCheck::execute() {
+ mStatus = NANDCheck(mNeededBlocks, mNeededFiles, &mResult);
+ return true;
+}
+
+NandRequestCreate::NandRequestCreate(const char *filePath, u8 perm, u8 attr) {
+ mPerm = perm;
+ mAttr = attr;
+ mFilePath = filePath;
+}
+
+const char *splitComponent(const char *inPath, char *outPath, size_t size) {
+ char *end = outPath + size - 1;
+ while (true) {
+ if (outPath >= end) {
+ break;
+ }
+ char curr = inPath[0];
+ char next = inPath[1];
+ inPath++;
+ *outPath = curr;
+ outPath++;
+ if (next == '\0' || next == '/') {
+ break;
+ }
+ }
+
+ *outPath = '\0';
+ char curr = *inPath;
+ if (curr != '/') {
+ return inPath;
+ }
+ return inPath + 1;
+}
+
+extern "C" NANDResult NANDChangeDir(const char *path);
+extern "C" NANDResult NANDCreateDir(const char *path, u8 perm, u8 attr);
+
+bool NandRequestCreate::execute() {
+ char homeDir[64];
+ char pathComponent[64];
+
+ mStatus = NANDGetHomeDir(homeDir);
+ if (mStatus != NAND_RESULT_OK) {
+ return true;
+ }
+
+ const char *ptr = mFilePath;
+ if (ptr[0] == '/') {
+ ptr = splitComponent(ptr, pathComponent, sizeof(pathComponent));
+ } else {
+ std::strncpy(pathComponent, homeDir, sizeof(pathComponent));
+ }
+
+ mStatus = NANDChangeDir(pathComponent);
+ if (mStatus != NAND_RESULT_OK) {
+ return true;
+ }
+
+ const char *component = splitComponent(ptr, pathComponent, sizeof(pathComponent));
+ while (component[0] != '\0') {
+ mStatus = NANDCreateDir(pathComponent, mPerm, mAttr);
+ if (mStatus != NAND_RESULT_OK && mStatus != NAND_RESULT_EXISTS) {
+ return true;
+ }
+ mStatus = NANDChangeDir(pathComponent);
+ if (mStatus != NAND_RESULT_OK) {
+ return true;
+ }
+ component = splitComponent(component, pathComponent, sizeof(pathComponent));
+ }
+
+ mStatus = NANDChangeDir(homeDir);
+ if (mStatus != NAND_RESULT_OK) {
+ return true;
+ }
+
+ mStatus = NANDCreate(mFilePath, mPerm, mAttr);
+ return mStatus == NAND_RESULT_OK || mStatus == NAND_RESULT_EXISTS;
+}
+
+NandRequestWrite::NandRequestWrite(const char *someString, void *data, size_t dataSize) {
+ mData = data;
+ mDataSize = dataSize;
+ mFailedWrite = false;
+ mFilePath = someString;
+}
+
+extern "C" NANDResult NANDSimpleSafeOpen(const char *path, NANDFileInfo *outInfo, int, void *buf, size_t bufLen);
+extern "C" NANDResult NANDSimpleSafeCancel(NANDFileInfo *info);
+extern "C" NANDResult NANDSimpleSafeClose(NANDFileInfo *info);
+
+bool NandRequestWrite::execute() {
+ NANDFileInfo info;
+ mStatus = NANDSimpleSafeOpen(
+ mFilePath, &info, 2, NandRequestThread::getInstance()->getBuf(), NandRequestThread::getInstance()->getBufSize()
+ );
+ if (mStatus != NAND_RESULT_OK) {
+ NANDResult res = NANDSimpleSafeCancel(&info);
+ if (res != NAND_RESULT_OK) {
+ mStatus = res;
+ }
+ return true;
+ }
+
+ mStatus = NANDWrite(&info, mData, mDataSize);
+ if (mStatus == NAND_RESULT_ECC_CRIT || mStatus == NAND_RESULT_AUTHENTICATION) {
+ mStatus = NANDSimpleSafeCancel(&info);
+ if (mStatus == NAND_RESULT_OK) {
+ mFailedWrite = true;
+ }
+ return true;
+ }
+
+ NANDResult res = NANDSimpleSafeClose(&info);
+ if (mStatus != mDataSize) {
+ mFailedWrite = true;
+ } else {
+ mStatus = res;
+ }
+
+ return true;
+}
+
+bool NandRequestHolderBase::isCompleted() const {
+ if (mpRequest != nullptr) {
+ return mpRequest->bHandled;
+ }
+ return true;
+}
+
+NANDResult NandRequestHolderBase::getStatus() const {
+ if (mpRequest != nullptr) {
+ return mpRequest->getStatus();
+ }
+ return NAND_RESULT_BUSY;
+}
+
+bool NandRequestHolderBase::runToCompletion() {
+ if (mpRequest == nullptr) {
+ return true;
+ }
+
+ do {
+ } while (!isCompleted());
+ NandRequest::free(mpRequest);
+ mpRequest = nullptr;
+
+ return true;
+}
+
+bool NandRequestCheckHolder::check(u32 neededBlocks, u32 neededFiles) {
+ if (mpRequest != nullptr) {
+ return false;
+ }
+
+ NandRequestCheck *req = NandRequestThread::getInstance()->checkRequest(neededBlocks, neededFiles);
+ if (req == nullptr) {
+ return false;
+ }
+ mpRequest = req;
+ return true;
+}
+
+u32 NandRequestCheckHolder::getCheckResult() {
+ return static_cast<NandRequestCheck *>(mpRequest)->mResult;
+}
+
+bool NandRequestCreateHolder::create(const char *filePath, u8 perm, u8 attr) {
+ if (mpRequest != nullptr) {
+ return false;
+ }
+
+ NandRequestCreate *req = NandRequestThread::getInstance()->createRequest(filePath, perm, attr);
+ if (req == nullptr) {
+ return false;
+ }
+ mpRequest = req;
+ return true;
+}
+
+bool NandRequestWriteHolder::write(const char *filePath, void *data, size_t dataSize) {
+ if (mpRequest != nullptr) {
+ return false;
+ }
+
+ NandRequestWrite *req = NandRequestThread::getInstance()->writeRequest(filePath, data, dataSize);
+ if (req == nullptr) {
+ return false;
+ }
+ mpRequest = req;
+ return true;
+}
+
+bool NandRequestWriteHolder::failedWrite() {
+ return static_cast<NandRequestWrite *>(mpRequest)->mFailedWrite;
+}