diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 1bf3755eeb..05e6bdc9ae 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -68,6 +68,8 @@ // dependency to be removed #include "gui/guiWrapper.h" +#include "Cafe/OS/libs/coreinit/coreinit_FS.h" + #include #if BOOST_OS_LINUX @@ -1008,6 +1010,87 @@ namespace CafeSystem sSystemRunning = false; } + void PauseTitle() + { + if (!sSystemRunning) + return; + coreinit::SuspendActiveThreads(); + iosu::pdm::Stop(); + sSystemRunning = false; + } + + void ResumeTitle() + { + if (sSystemRunning) + return; + coreinit::ResumeActiveThreads(); + iosu::pdm::StartTrackingTime(GetForegroundTitleId()); + sSystemRunning = true; + } + + void SaveState(std::string path) + { + cemuLog_log(LogType::SaveStates, "Saving state..."); + MemStreamWriter writer(0); + // pause game + PauseTitle(); + // memory + memory_Serialize(writer); + + + nn::temp::save(writer); + nn::aoc::save(writer); + osLib_save(writer); + iosu::kernel::save(writer); + iosu::fsa::save(writer); + iosu::odm::save(writer); + + // gpu + writer.writeData(LatteGPUState.contextRegister, sizeof(LatteGPUState.contextRegister)); + writer.writeData(LatteGPUState.contextRegisterShadowAddr, sizeof(LatteGPUState.contextRegister)); + writer.writeData(LatteGPUState.sharedArea, sizeof(gx2GPUSharedArea_t)); + + FileStream* stream = FileStream::createFile(path); + stream->writeData(writer.getResult().data(), writer.getResult().size_bytes()); + delete stream; + cemuLog_log(LogType::SaveStates, "Saved state to {}.", path); + + ResumeTitle(/*isThreadRunning*/); + } + + void LoadState(std::string path) + { + PauseTitle(); + //coreinit::__OSDeleteAllActivePPCThreads(); + DestroyMemorySpace(); + + cemuLog_log(LogType::SaveStates, "Loading state...", path); + + auto data = FileStream::LoadIntoMemory(path); + assert(data.has_value()); + MemStreamReader reader(data->data(), data->size()); + + // memory + + memory_Deserialize(reader); + + nn::temp::restore(reader); + nn::aoc::restore(reader); + osLib_restore(reader); + iosu::kernel::restore(reader); + iosu::fsa::restore(reader); + iosu::odm::restore(reader); + + // gpu + reader.readData(LatteGPUState.contextRegister, sizeof(LatteGPUState.contextRegister)); + reader.readData(LatteGPUState.contextRegisterShadowAddr, sizeof(LatteGPUState.contextRegister)); + reader.readData(LatteGPUState.sharedArea, sizeof(gx2GPUSharedArea_t)); + + cemuLog_log(LogType::SaveStates, "Loaded state from {}.", path); + + ResumeTitle(/*isThreadRunning*/); + } + /* Virtual mlc storage */ void InitVirtualMlcStorage() diff --git a/src/Cafe/CafeSystem.h b/src/Cafe/CafeSystem.h index e9de8d7dd4..78c10c5a60 100644 --- a/src/Cafe/CafeSystem.h +++ b/src/Cafe/CafeSystem.h @@ -47,6 +47,12 @@ namespace CafeSystem void ShutdownTitle(); + void PauseTitle(); + void ResumeTitle(); + + void SaveState(std::string path); + void LoadState(std::string path); + std::string GetMlcStoragePath(TitleId titleId); void MlcStorageMountAllTitles(); diff --git a/src/Cafe/Filesystem/fsc.cpp b/src/Cafe/Filesystem/fsc.cpp index 031f2fb2a4..7bb5e4667e 100644 --- a/src/Cafe/Filesystem/fsc.cpp +++ b/src/Cafe/Filesystem/fsc.cpp @@ -338,6 +338,8 @@ class FSCVirtualFileDirectoryIterator : public FSCVirtualFile dirIterator->dirEntries.emplace_back(dirEntry); } + void Save(MemStreamWriter& writer) override; + private: void PopulateIterationList() { @@ -733,3 +735,76 @@ void fsc_init() { fsc_reset(); } + +template <> +void MemStreamWriter::write(const FSCVirtualFile::FSCDirIteratorState& v) +{ + write(v.index); + writePODVector(v.dirEntries); +} + +template <> +void MemStreamReader::read(FSCVirtualFile::FSCDirIteratorState& v) +{ + read(v.index); + readPODVector(v.dirEntries); +} + +void FSCVirtualFile::Save(MemStreamWriter& writer) +{ + writer.writeBool(dirIterator != nullptr); + if (dirIterator) writer.write(*dirIterator); + writer.writeBool(m_isAppend); +} + +void FSCVirtualFileDirectoryIterator::Save(MemStreamWriter& writer) +{ + writer.write((uint32)Child::DIRECTORY_ITERATOR); + writer.write(m_path); + writer.write(m_folders.size()); + for (auto& folder : m_folders) + { + folder->Save(writer); + } + FSCVirtualFile::Save(writer); +} + +#include "Cafe/Filesystem/fscDeviceHostFS.h" + +FSCVirtualFile* FSCVirtualFile::Restore(MemStreamReader& reader) +{ + FSCVirtualFile* file; + switch ((Child)reader.read()) + { + case Child::DIRECTORY_ITERATOR: + { + std::string path = reader.read(); + std::vector folders{}; + size_t size = reader.read(); + for (size_t i = 0; i < size; i++) + { + folders.push_back(Restore(reader)); + } + file = new FSCVirtualFileDirectoryIterator(path, folders); + break; + } + case Child::HOST: + { + std::string path = reader.read(); + FSC_ACCESS_FLAG flags = (FSC_ACCESS_FLAG)reader.read(); + sint32 status{}; + file = FSCVirtualFile_Host::OpenFile(path, flags, status); + file->fscSetSeek(reader.read()); + break; + } + default: + throw std::exception("Not implemented"); + } + if (reader.readBool()) + { + file->dirIterator = new FSCDirIteratorState; + reader.read(*file->dirIterator); + } + reader.readBool(file->m_isAppend); + return file; +} \ No newline at end of file diff --git a/src/Cafe/Filesystem/fsc.h b/src/Cafe/Filesystem/fsc.h index 8b8ed5ef2a..b380bb64d3 100644 --- a/src/Cafe/Filesystem/fsc.h +++ b/src/Cafe/Filesystem/fsc.h @@ -89,12 +89,20 @@ class fscDeviceC struct FSCVirtualFile { + enum class Child : uint32 + { + DIRECTORY_ITERATOR, HOST, WUACTX, WUDCTX, NONE + }; + struct FSCDirIteratorState { sint32 index; std::vector dirEntries; }; + virtual void Save(MemStreamWriter& writer); + static FSCVirtualFile* Restore(MemStreamReader& reader); + FSCVirtualFile() { diff --git a/src/Cafe/Filesystem/fscDeviceHostFS.cpp b/src/Cafe/Filesystem/fscDeviceHostFS.cpp index 85a04afecb..47ae761f8b 100644 --- a/src/Cafe/Filesystem/fscDeviceHostFS.cpp +++ b/src/Cafe/Filesystem/fscDeviceHostFS.cpp @@ -191,9 +191,11 @@ FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_F if (fs) { FSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_FILE); + vf->m_path.reset(new std::filesystem::path(path)); vf->m_fs = fs; vf->m_isWritable = writeAccessRequested; vf->m_fileSize = fs->GetSize(); + vf->m_accessFlags = accessFlags; fscStatus = FSC_STATUS_OK; return vf; } @@ -208,6 +210,7 @@ FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_F { FSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_DIRECTORY); vf->m_path.reset(new std::filesystem::path(path)); + vf->m_accessFlags = accessFlags; fscStatus = FSC_STATUS_OK; return vf; } @@ -292,4 +295,13 @@ class fscDeviceHostFSC : public fscDeviceC bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority) { return fsc_mount(mountPath, hostTargetPath, &fscDeviceHostFSC::instance(), nullptr, priority) == FSC_STATUS_OK; -} \ No newline at end of file +} + +void FSCVirtualFile_Host::Save(MemStreamWriter& writer) +{ + writer.write((uint32)Child::HOST); + writer.write(m_path->string()); + writer.write((uint32)m_accessFlags); + writer.write(m_seek); + FSCVirtualFile::Save(writer); +} diff --git a/src/Cafe/Filesystem/fscDeviceHostFS.h b/src/Cafe/Filesystem/fscDeviceHostFS.h index 7121594c02..0a7df4cd4f 100644 --- a/src/Cafe/Filesystem/fscDeviceHostFS.h +++ b/src/Cafe/Filesystem/fscDeviceHostFS.h @@ -18,6 +18,8 @@ class FSCVirtualFile_Host : public FSCVirtualFile void fscSetFileLength(uint64 endOffset) override; bool fscDirNext(FSCDirEntry* dirEntry) override; + void Save(MemStreamWriter& writer) override; + private: FSCVirtualFile_Host(uint32 type) : m_type(type) {}; @@ -31,4 +33,6 @@ class FSCVirtualFile_Host : public FSCVirtualFile // directory std::unique_ptr m_path{}; std::unique_ptr m_dirIterator{}; + // serialization + FSC_ACCESS_FLAG m_accessFlags; }; \ No newline at end of file diff --git a/src/Cafe/Filesystem/fscDeviceWua.cpp b/src/Cafe/Filesystem/fscDeviceWua.cpp index f9014bdb43..e5f23a9e44 100644 --- a/src/Cafe/Filesystem/fscDeviceWua.cpp +++ b/src/Cafe/Filesystem/fscDeviceWua.cpp @@ -107,6 +107,11 @@ class FSCDeviceWuaFileCtx : public FSCVirtualFile return true; } + void Save(MemStreamWriter& writer) override + { + throw std::exception("Not implemented"); + } + private: ZArchiveReader* m_archive{nullptr}; sint32 m_fscType; diff --git a/src/Cafe/Filesystem/fscDeviceWud.cpp b/src/Cafe/Filesystem/fscDeviceWud.cpp index 517c85734e..5dc8ae5553 100644 --- a/src/Cafe/Filesystem/fscDeviceWud.cpp +++ b/src/Cafe/Filesystem/fscDeviceWud.cpp @@ -108,6 +108,11 @@ class FSCDeviceWudFileCtx : public FSCVirtualFile return true; } + void Save(MemStreamWriter& writer) override + { + throw std::exception("Not implemented"); + } + private: FSTVolume* m_volume{nullptr}; sint32 m_fscType; diff --git a/src/Cafe/HW/MMU/MMU.cpp b/src/Cafe/HW/MMU/MMU.cpp index 04ee8877e6..8793d8c423 100644 --- a/src/Cafe/HW/MMU/MMU.cpp +++ b/src/Cafe/HW/MMU/MMU.cpp @@ -412,6 +412,57 @@ void memory_createDump() } } +template<> +void MemStreamWriter::write(const MMURange& v) +{ + writeBool(v.m_isMapped); + write(v.baseAddress); + write((uint8)v.areaId); + write((uint8)v.flags); + write(v.name); + write(v.size); + write(v.initSize); +} + +template <> +void MemStreamReader::read(MMURange& v) +{ + bool needsMapped = readBool(); + v.m_isMapped = false; + read(v.baseAddress); + v.areaId = (MMU_MEM_AREA_ID)read(); + v.flags = (MMURange::MFLAG)read(); + read(v.name); + read(v.size); + read(v.initSize); + if (needsMapped) + v.mapMem(); +} + +void memory_Serialize(MemStreamWriter& s) +{ + for (auto& itr : g_mmuRanges) + { + s.write(*itr); + if (itr->isMapped()) + { + s.writeData(memory_base + itr->getBase(), itr->getSize()); + } + } +} + +void memory_Deserialize(MemStreamReader& s) +{ + for (auto& itr : g_mmuRanges) + { + s.read(*itr); + if (itr->isMapped()) + { + s.readData(memory_base + itr->getBase(), itr->getSize()); + } + } +} + namespace MMU { // MMIO access handler diff --git a/src/Cafe/HW/MMU/MMU.h b/src/Cafe/HW/MMU/MMU.h index 794785fafc..3090e3c966 100644 --- a/src/Cafe/HW/MMU/MMU.h +++ b/src/Cafe/HW/MMU/MMU.h @@ -1,5 +1,7 @@ #pragma once +#include "util/helpers/Serializer.h" + void memory_init(); void memory_mapForCurrentTitle(); void memory_unmapForCurrentTitle(); @@ -108,14 +110,16 @@ struct MMURange bool isOptional() const { return (flags & MFLAG::FLAG_OPTIONAL) != 0; }; bool isMappedEarly() const { return (flags & MFLAG::FLAG_MAP_EARLY) != 0; }; - const uint32 baseAddress; - const uint32 initSize; // initial size - const std::string name; - const MFLAG flags; - const MMU_MEM_AREA_ID areaId; + uint32 baseAddress; + uint32 initSize; // initial size + std::string name; + MFLAG flags; + MMU_MEM_AREA_ID areaId; // runtime parameters uint32 size; bool m_isMapped{}; + friend class MemStreamWriter; + friend class MemStreamReader; }; @@ -203,6 +207,9 @@ uint8 memory_readU8(uint32 address); void memory_createDump(); +void memory_Serialize(MemStreamWriter& s); +void memory_Deserialize(MemStreamReader& s); + template void memory_readBytes(VAddr address, std::array& buffer) { diff --git a/src/Cafe/IOSU/ODM/iosu_odm.cpp b/src/Cafe/IOSU/ODM/iosu_odm.cpp index aae3c503e3..e283fb631e 100644 --- a/src/Cafe/IOSU/ODM/iosu_odm.cpp +++ b/src/Cafe/IOSU/ODM/iosu_odm.cpp @@ -135,6 +135,26 @@ namespace iosu s_threadInitialized = false; } + void save(MemStreamWriter& s) + { + s.writeSection("iosu_odm"); + s.writeAtomic(s_requestStop); + s.writeAtomic(s_isRunning); + s.writeAtomic(s_threadInitialized); + s.write(s_msgQueueId); + s.writeMPTR(_s_msgBuffer); + } + + void restore(MemStreamReader& s) + { + s.readSection("iosu_odm"); + s.readAtomic(s_requestStop); + s.readAtomic(s_isRunning); + s.readAtomic(s_threadInitialized); + s.read(s_msgQueueId); + s.readMPTR(_s_msgBuffer); + } + void Initialize() { if (s_isRunning.exchange(true)) diff --git a/src/Cafe/IOSU/ODM/iosu_odm.h b/src/Cafe/IOSU/ODM/iosu_odm.h index f5f721a171..98ea77140f 100644 --- a/src/Cafe/IOSU/ODM/iosu_odm.h +++ b/src/Cafe/IOSU/ODM/iosu_odm.h @@ -4,6 +4,9 @@ namespace iosu { namespace odm { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void Initialize(); void Shutdown(); } diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.cpp b/src/Cafe/IOSU/PDM/iosu_pdm.cpp index d94b1dbfc3..61d8ec196d 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.cpp +++ b/src/Cafe/IOSU/PDM/iosu_pdm.cpp @@ -409,6 +409,15 @@ namespace iosu } } + void save(MemStreamWriter& s) + { + + } + void restore(MemStreamReader& s) + { + + } + class : public ::IOSUModule { void PDMLoadAll() diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.h b/src/Cafe/IOSU/PDM/iosu_pdm.h index 0dd8a39d2d..a4e891ec51 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.h +++ b/src/Cafe/IOSU/PDM/iosu_pdm.h @@ -5,6 +5,9 @@ namespace iosu { namespace pdm { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + inline constexpr size_t NUM_PLAY_STATS_ENTRIES = 256; inline constexpr size_t NUM_PLAY_DIARY_ENTRIES_MAX = 18250; // 0x474A diff --git a/src/Cafe/IOSU/fsa/iosu_fsa.cpp b/src/Cafe/IOSU/fsa/iosu_fsa.cpp index 1429d08333..138d8d39b9 100644 --- a/src/Cafe/IOSU/fsa/iosu_fsa.cpp +++ b/src/Cafe/IOSU/fsa/iosu_fsa.cpp @@ -36,7 +36,9 @@ namespace iosu } }; - std::array sFSAClientArray; + static constexpr int const sFSAClientArraySize = 624; + + std::array sFSAClientArray; IOS_ERROR FSAAllocateClient(sint32& indexOut) { @@ -169,6 +171,8 @@ namespace iosu } class _FSAHandleTable { + friend class MemStreamWriter; + friend class MemStreamReader; struct _FSAHandleResource { bool isAllocated{false}; @@ -227,9 +231,10 @@ namespace iosu return it.fscFile; } + static constexpr int const m_handleTableSize = 0x3C0; private: uint32 m_currentCounter = 1; - std::array<_FSAHandleResource, 0x3C0> m_handleTable; + std::array<_FSAHandleResource, m_handleTableSize> m_handleTable; }; _FSAHandleTable sFileHandleTable; @@ -904,3 +909,85 @@ namespace iosu } } // namespace fsa } // namespace iosu + +template <> +void MemStreamWriter::write(const iosu::fsa::FSAClient& v) +{ + write(v.workingDirectory); + writeBool(v.isAllocated); +} + +template <> +void MemStreamReader::read(iosu::fsa::FSAClient& v) +{ + read(v.workingDirectory); + readBool(v.isAllocated); +} + +template <> +void MemStreamWriter::write(const iosu::fsa::_FSAHandleTable& v) +{ + write(v.m_currentCounter); + for (sint32 i = 0; i < v.m_handleTable.size(); i++) + { + write(v.m_handleTable[i].handleCheckValue); + writeBool(v.m_handleTable[i].isAllocated); + + writeBool(v.m_handleTable[i].fscFile != nullptr); + if (v.m_handleTable[i].fscFile != nullptr) v.m_handleTable[i].fscFile->Save(*this); + } +} + +template <> +void MemStreamReader::read(iosu::fsa::_FSAHandleTable& v) +{ + read(v.m_currentCounter); + for (sint32 i = 0; i < v.m_handleTable.size(); i++) + { + read(v.m_handleTable[i].handleCheckValue); + readBool(v.m_handleTable[i].isAllocated); + + if (readBool()) + { + v.m_handleTable[i].fscFile = FSCVirtualFile::Restore(*this); + } + else + { + v.m_handleTable[i].fscFile = nullptr; + } + } +} + +namespace iosu +{ + namespace fsa + { + void save(MemStreamWriter& s) + { + s.writeSection("iosu_fsa"); + s.write(sFSAIoMsgQueue); + s.writeMPTR(_m_sFSAIoMsgQueueMsgBuffer); + + for (sint32 i = 0; i < sFSAClientArraySize; i++) + { + s.write(sFSAClientArray[i]); + } + s.write(sDirHandleTable); + s.write(sFileHandleTable); + } + + void restore(MemStreamReader& s) + { + s.readSection("iosu_fsa"); + s.read(sFSAIoMsgQueue); + s.readMPTR(_m_sFSAIoMsgQueueMsgBuffer); + + for (sint32 i = 0; i < sFSAClientArraySize; i++) + { + s.read(sFSAClientArray[i]); + } + s.read(sDirHandleTable); + s.read(sFileHandleTable); + } + } // namespace fsa +} // namespace iosu \ No newline at end of file diff --git a/src/Cafe/IOSU/fsa/iosu_fsa.h b/src/Cafe/IOSU/fsa/iosu_fsa.h index 8181a4a8dc..49c36a2d35 100644 --- a/src/Cafe/IOSU/fsa/iosu_fsa.h +++ b/src/Cafe/IOSU/fsa/iosu_fsa.h @@ -213,5 +213,8 @@ namespace iosu void Initialize(); void Shutdown(); + + void save(MemStreamWriter& writer); + void restore(MemStreamReader& reader); } // namespace fsa } // namespace iosu diff --git a/src/Cafe/IOSU/kernel/iosu_kernel.cpp b/src/Cafe/IOSU/kernel/iosu_kernel.cpp index 666e0373ee..0b35d3bdd1 100644 --- a/src/Cafe/IOSU/kernel/iosu_kernel.cpp +++ b/src/Cafe/IOSU/kernel/iosu_kernel.cpp @@ -379,11 +379,13 @@ namespace iosu /* IPC */ + static constexpr size_t IOCTLV_VECTOR_ARRAY_SIZE = 8; + struct IOSDispatchableCommand { // stores a copy of incoming IPC requests with some extra information required for replies IPCCommandBody body; // our dispatchable copy - IPCIoctlVector vecCopy[8]; // our copy of the Ioctlv vector array + IPCIoctlVector vecCopy[IOCTLV_VECTOR_ARRAY_SIZE]; // our copy of the Ioctlv vector array IPCCommandBody* originalBody; // the original command that was sent to us uint32 ppcCoreIndex; IOSDevHandle replyHandle; // handle for outgoing replies @@ -775,6 +777,131 @@ namespace iosu return static_cast(&sIOSUModuleKernel); } + } +} + +template <> +void MemStreamWriter::write(const iosu::kernel::IOSMessageQueue& v) +{ + write(v.ukn00); + write(v.ukn04); + write(v.numQueuedMessages); + write(v.readIndex); + write(v.msgArraySize); + writeMPTR(v.msgArray); + write(v.queueHandle); + write(v.ukn1C); +} + +template <> +void MemStreamReader::read(iosu::kernel::IOSMessageQueue& v) +{ + read(v.ukn00); + read(v.ukn04); + read(v.numQueuedMessages); + read(v.readIndex); + read(v.msgArraySize); + readMPTR(v.msgArray); + read(v.queueHandle); + read(v.ukn1C); +} + +template <> +void MemStreamWriter::write(const iosu::kernel::IOSResourceManager& v) +{ + writeBool(v.isSet); + write(v.path); + write(v.msgQueueId); +} + +template <> +void MemStreamReader::read(iosu::kernel::IOSResourceManager& v) +{ + readBool(v.isSet); + read(v.path); + read(v.msgQueueId); +} + +template <> +void MemStreamWriter::write(const iosu::kernel::IPCActiveDeviceHandle& v) +{ + writeBool(v.isSet); + write(v.handleCheckValue); + write(v.path); + write(v.msgQueueId); + writeBool(v.hasDispatchTargetHandle); + write(v.dispatchTargetHandle); +} + +template <> +void MemStreamReader::read(iosu::kernel::IPCActiveDeviceHandle& v) +{ + readBool(v.isSet); + read(v.handleCheckValue); + read(v.path); + read(v.msgQueueId); + readBool(v.hasDispatchTargetHandle); + read(v.dispatchTargetHandle); +} + +namespace iosu +{ + namespace kernel + { + void save(MemStreamWriter& s) + { + s.write(sMsgQueuePool.size()); + for (const auto& i : sMsgQueuePool) + s.write(i); + + s.write(sDeviceResources.size()); + for (const auto& i : sDeviceResources) + s.write(i); + + s.writeMPTR(sIPCDispatchableCommandPool); + + size_t sIPCFreeDispatchableCommandsSize = sIPCFreeDispatchableCommands.size(); + s.write(sIPCFreeDispatchableCommandsSize); + while (sIPCFreeDispatchableCommandsSize) + { + IOSDispatchableCommand* front = sIPCFreeDispatchableCommands.front(); + sIPCFreeDispatchableCommands.pop(); + s.writePTR(front); + sIPCFreeDispatchableCommands.push(front); + sIPCFreeDispatchableCommandsSize--; + } + + s.write(MAX_NUM_ACTIVE_DEV_HANDLES); + for (uint32 i = 0; i < MAX_NUM_ACTIVE_DEV_HANDLES; i++) + s.write(sActiveDeviceHandles[i]); + } + + void restore(MemStreamReader& s) + { + cemu_assert(s.read() == sMsgQueuePool.size()); + for (auto& i : sMsgQueuePool) + s.read(i); + + cemu_assert(s.read() == sDeviceResources.size()); + for (auto& i : sDeviceResources) + s.read(i); + s.readMPTR(sIPCDispatchableCommandPool); + + size_t sIPCFreeDispatchableCommandsSize = s.read(); + cemu_assert(sIPCFreeDispatchableCommandsSize == sIPCFreeDispatchableCommands.size()); + while (!sIPCFreeDispatchableCommands.empty()) + sIPCFreeDispatchableCommands.pop(); + for (uint32 i = 0; i < sIPCFreeDispatchableCommandsSize; i++) + { + IOSDispatchableCommand* cmd = nullptr; + s.readPTR(cmd); + sIPCFreeDispatchableCommands.push(cmd); + } + + cemu_assert(s.read() == MAX_NUM_ACTIVE_DEV_HANDLES); + for (uint32 i = 0; i < MAX_NUM_ACTIVE_DEV_HANDLES; i++) + s.read(sActiveDeviceHandles[i]); + } } } \ No newline at end of file diff --git a/src/Cafe/IOSU/kernel/iosu_kernel.h b/src/Cafe/IOSU/kernel/iosu_kernel.h index 0355c118f6..6236afbae1 100644 --- a/src/Cafe/IOSU/kernel/iosu_kernel.h +++ b/src/Cafe/IOSU/kernel/iosu_kernel.h @@ -24,5 +24,8 @@ namespace iosu void IPCSubmitFromCOS(uint32 ppcCoreIndex, IPCCommandBody* cmd); IOSUModule* GetModule(); + + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); } } \ No newline at end of file diff --git a/src/Cafe/OS/common/OSCommon.cpp b/src/Cafe/OS/common/OSCommon.cpp index 5297f201ea..69e4bad0a7 100644 --- a/src/Cafe/OS/common/OSCommon.cpp +++ b/src/Cafe/OS/common/OSCommon.cpp @@ -187,6 +187,47 @@ void osLib_returnFromFunction64(PPCInterpreter_t* hCPU, uint64 returnValue64) hCPU->instructionPointer = hCPU->spr.LR; } +void osLib_save(MemStreamWriter& s) +{ + coreinit_save(s); + dmae_save(s); + padscore::save(s); + nnAct_save(s); + nn::acp::save(s); + nnBoss_save(s); + nn::nfp::save(s); + nnUds_save(s); + nn::ndm::save(s); + nn::save::save(s); + nsysnet_save(s); + nn::fp::save(s); + nn::olv::save(s); + nlibcurl::save(s); + nsyshid::save(s); + camera::save(s); + proc_ui::save(s); +} +void osLib_restore(MemStreamReader& s) +{ + coreinit_restore(s); + dmae_restore(s); + padscore::restore(s); + nnAct_restore(s); + nn::acp::restore(s); + nnBoss_restore(s); + nn::nfp::restore(s); + nnUds_restore(s); + nn::ndm::restore(s); + nn::save::restore(s); + nsysnet_restore(s); + nn::fp::restore(s); + nn::olv::restore(s); + nlibcurl::restore(s); + nsyshid::restore(s); + camera::restore(s); + proc_ui::restore(s); +} + void osLib_load() { // load HLE modules diff --git a/src/Cafe/OS/common/OSCommon.h b/src/Cafe/OS/common/OSCommon.h index 34f207bb31..f9068169bb 100644 --- a/src/Cafe/OS/common/OSCommon.h +++ b/src/Cafe/OS/common/OSCommon.h @@ -6,6 +6,9 @@ struct PPCInterpreter_t; #define OSLIB_FUNCTIONTABLE_TYPE_FUNCTION (1) #define OSLIB_FUNCTIONTABLE_TYPE_POINTER (2) +void osLib_save(MemStreamWriter& s); +void osLib_restore(MemStreamReader& s); + void osLib_load(); void osLib_generateHashFromName(const char* name, uint32* hashA, uint32* hashB); sint32 osLib_getFunctionIndex(const char* libraryName, const char* functionName); diff --git a/src/Cafe/OS/libs/camera/camera.cpp b/src/Cafe/OS/libs/camera/camera.cpp index efb8013d8c..bb3134224f 100644 --- a/src/Cafe/OS/libs/camera/camera.cpp +++ b/src/Cafe/OS/libs/camera/camera.cpp @@ -242,6 +242,29 @@ namespace camera g_cameraCounter = 0; } + void save(MemStreamWriter& s) + { + s.writeSection("camera"); + + s.writePODVector(g_table_cameraHandles); + s.writePODVector(g_activeCameraInstances); + s.writeAtomic(g_cameraCounter); + s.writeMPTR(g_alarm_camera); + s.writeMPTR(g_cameraHandlerParam); + } + void restore(MemStreamReader& s) + { + s.readSection("camera"); + + std::unique_lock _lock(g_mutex_camera); + + s.readPODVector(g_table_cameraHandles); + s.readPODVector(g_activeCameraInstances); + s.readAtomic(g_cameraCounter); + s.readMPTR(g_alarm_camera); + s.readMPTR(g_cameraHandlerParam); + } + void load() { reset(); @@ -253,5 +276,4 @@ namespace camera cafeExportRegister("camera", CAMClose, LogType::Placeholder); cafeExportRegister("camera", CAMSubmitTargetSurface, LogType::Placeholder); } -} - +} \ No newline at end of file diff --git a/src/Cafe/OS/libs/camera/camera.h b/src/Cafe/OS/libs/camera/camera.h index 04248bbc20..6b3d48b1de 100644 --- a/src/Cafe/OS/libs/camera/camera.h +++ b/src/Cafe/OS/libs/camera/camera.h @@ -6,5 +6,8 @@ namespace camera sint32 CAMOpen(sint32 camHandle); sint32 CAMClose(sint32 camHandle); + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit.cpp b/src/Cafe/OS/libs/coreinit/coreinit.cpp index 00327a97b4..a2796719b5 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit.cpp @@ -303,6 +303,60 @@ namespace coreinit } }; +void coreinit_save(MemStreamWriter& s) +{ + s.writeSection("coreinit"); + s.writeNullableData(gCoreinitData, sizeof(coreinitData_t)); + s.write(placeholderFont); + s.write(placeholderFontSize); + + coreinit_Init_Save(s); + coreinit::SysHeap_Save(s); + coreinit::Thread_Save(s); + coreinit::MEM_Save(s); + coreinit::FG_Save(s); + coreinit::OverlayArena_Save(s); + coreinit::DynLoad_Save(s); + coreinit::GHS_Save(s); + coreinit::LockedCache_Save(s); + coreinit::Alarm_Save(s); + coreinit::FS_Save(s); + coreinit::SystemInfo_Save(s); + coreinit::Synchronization_Save(s); + coreinit::MessageQueue_Save(s); + coreinit::IPC_Save(s); + coreinit::MemoryMapping_Save(s); + coreinit::CodeGen_Save(s); + coreinit_Callbacks_Save(s); +} + +void coreinit_restore(MemStreamReader& s) +{ + s.readSection("coreinit"); + s.readNullableData(gCoreinitData, sizeof(coreinitData_t)); + s.read(placeholderFont); + s.read(placeholderFontSize); + + coreinit_Init_Restore(s); + coreinit::SysHeap_Restore(s); + coreinit::Thread_Restore(s); + coreinit::MEM_Restore(s); + coreinit::FG_Restore(s); + coreinit::OverlayArena_Restore(s); + coreinit::DynLoad_Restore(s); + coreinit::GHS_Restore(s); + coreinit::LockedCache_Restore(s); + coreinit::Alarm_Restore(s); + coreinit::FS_Restore(s); + coreinit::SystemInfo_Restore(s); + coreinit::Synchronization_Restore(s); + coreinit::MessageQueue_Restore(s); + coreinit::IPC_Restore(s); + coreinit::MemoryMapping_Restore(s); + coreinit::CodeGen_Restore(s); + coreinit_Callbacks_Restore(s); +} + void coreinit_load() { coreinit::InitializeCore(); diff --git a/src/Cafe/OS/libs/coreinit/coreinit.h b/src/Cafe/OS/libs/coreinit/coreinit.h index 74aab9b29e..8cf616facf 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit.h +++ b/src/Cafe/OS/libs/coreinit/coreinit.h @@ -11,8 +11,14 @@ void InitializeAsyncCallback(); void coreinitAsyncCallback_add(MPTR functionMPTR, uint32 numParameters, uint32 r3 = 0, uint32 r4 = 0, uint32 r5 = 0, uint32 r6 = 0, uint32 r7 = 0, uint32 r8 = 0, uint32 r9 = 0, uint32 r10 = 0); void coreinitAsyncCallback_addWithLock(MPTR functionMPTR, uint32 numParameters, uint32 r3 = 0, uint32 r4 = 0, uint32 r5 = 0, uint32 r6 = 0, uint32 r7 = 0, uint32 r8 = 0, uint32 r9 = 0, uint32 r10 = 0); +void coreinit_Callbacks_Save(MemStreamWriter& s); +void coreinit_Callbacks_Restore(MemStreamReader& s); + // misc +void coreinit_save(MemStreamWriter& s); +void coreinit_restore(MemStreamReader& s); + void coreinit_load(); // coreinit shared memory @@ -32,6 +38,9 @@ extern CoreinitSharedData* gCoreinitData; // coreinit init void coreinit_start(PPCInterpreter_t* hCPU); +void coreinit_Init_Save(MemStreamWriter& s); +void coreinit_Init_Restore(MemStreamReader& s); + MPTR OSAllocFromSystem(uint32 size, uint32 alignment); void OSFreeToSystem(MPTR mem); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp index ae2d1e63e2..bae508ffb3 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp @@ -247,7 +247,7 @@ namespace coreinit } else { - alarm->nextTime = _swapEndianU64(startTime); + alarm->nextTime = _swapEndianU64(nextTime); alarm->period = 0; alarm->handler = _swapEndianU32(handlerFunc); } @@ -305,6 +305,68 @@ namespace coreinit __OSUnlockScheduler(); } + void Alarm_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_Alarm"); + + s.writeMPTR(g_alarmEvent); + s.writeMPTR(g_alarmThread); + s.writeMPTR(_g_alarmThreadStack); + s.writeMPTR(_g_alarmThreadName); + + s.write(coreinit_getOSTime()); + + s.write((uint64)g_activeAlarms.size()); + for (auto& itr : g_activeAlarms) + { + s.write(memory_getVirtualOffsetFromPointer(itr.first)); + s.write(itr.second->getNextFire()); + } + } + + void Alarm_Restore(MemStreamReader& s) + { + OSAlarm_Shutdown(); + + s.readSection("coreinit_Alarm"); + + s.readMPTR(g_alarmEvent); + s.readMPTR(g_alarmThread); + s.readMPTR(_g_alarmThreadStack); + s.readMPTR(_g_alarmThreadName); + + uint64 currentTime = coreinit_getOSTime(); + uint64_t timeOffset = currentTime - s.read(); + + size_t alms = s.read(); + for (size_t alm = 0; alm < alms; alm++) + { + OSAlarm_t* alarm = (OSAlarm_t*)memory_getPointerFromVirtualOffset(s.read()); + + uint64 startTime = _swapEndianU64(alarm->startTime) + timeOffset; + uint64 nextTime = _swapEndianU64(alarm->nextTime) + timeOffset; + //uint64 nextTime = startTime; + + uint64 period = _swapEndianU64(alarm->period); + + if (period != 0) + { + //uint64 ticksSinceStart = currentTime - startTime; + //uint64 numPeriods = ticksSinceStart / period; + + //nextTime = startTime + (numPeriods + 1ull) * period; + + alarm->startTime = _swapEndianU64(startTime); + } + alarm->nextTime = _swapEndianU64(nextTime); + + uint64 nextFire = s.read() + timeOffset; + __OSLockScheduler(); + g_activeAlarms[alarm] = OSHostAlarmCreate(nextFire, period, __OSHostAlarmTriggered, nullptr); + __OSUnlockScheduler(); + } + } + void _OSAlarmThread(PPCInterpreter_t* hCPU) { while( true ) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.h b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.h index 472d4f21c9..5b75570f61 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.h @@ -47,6 +47,9 @@ namespace coreinit void OSAlarm_Shutdown(); + void Alarm_Save(MemStreamWriter& s); + void Alarm_Restore(MemStreamReader& s); + void alarm_update(); void InitializeAlarm(); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp index aef7e5aa0b..e080c3cbca 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp @@ -31,6 +31,19 @@ struct CoreinitAsyncCallback s_asyncCallbackSpinlock.unlock(); } + static std::vector& getPool() + { + return s_asyncCallbackPool; + } + + static std::vector& getQueue() + { + return s_asyncCallbackQueue; + } + + friend void ci_Callbacks_Save(MemStreamWriter& s); + friend void ci_Callbacks_Restore(MemStreamReader& s); + private: void doCall() { @@ -104,6 +117,28 @@ void coreinitAsyncCallback_add(MPTR functionMPTR, uint32 numParameters, uint32 r coreinitAsyncCallback_addWithLock(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10); } +void coreinit_Callbacks_Save(MemStreamWriter& s) +{ + s.writeSection("coreinit_Callbacks"); + s.writeMPTR(g_coreinitCallbackThread); + s.writeMPTR(_g_coreinitCallbackThreadStack); + s.writeMPTR(g_asyncCallbackAsync); + s.writeMPTR(_g_coreinitCBThreadName); + s.writePODVector(CoreinitAsyncCallback::getPool()); + s.writePODVector(CoreinitAsyncCallback::getQueue()); +} + +void coreinit_Callbacks_Restore(MemStreamReader& s) +{ + s.readSection("coreinit_Callbacks"); + s.readMPTR(g_coreinitCallbackThread); + s.readMPTR(_g_coreinitCallbackThreadStack); + s.readMPTR(g_asyncCallbackAsync); + s.readMPTR(_g_coreinitCBThreadName); + s.readPODVector(CoreinitAsyncCallback::getPool()); + s.readPODVector(CoreinitAsyncCallback::getQueue()); +} + void InitializeAsyncCallback() { coreinit::OSInitSemaphore(g_asyncCallbackAsync.GetPtr(), 0); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.cpp b/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.cpp index f0e0bd8090..d4d70bc0b1 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.cpp @@ -25,9 +25,10 @@ namespace coreinit } } + static constexpr uint32 const codegenSize = 0x01000000; // todo: Read from cos.xml + void OSGetCodegenVirtAddrRange(betype* rangeStart, betype* rangeSize) { - uint32 codegenSize = 0x01000000; // todo: Read from cos.xml //debug_printf("OSGetCodegenVirtAddrRange(0x%08x,0x%08x)\n", hCPU->gpr[3], hCPU->gpr[4]); // on first call, allocate range if( coreinitCodeGen.rangeIsAllocated == false ) @@ -136,6 +137,26 @@ namespace coreinit return true; } + void CodeGen_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_CodeGen"); + s.writeBool(coreinitCodeGen.rangeIsAllocated); + s.write(coreinitCodeGen.rangeStart); + s.write(coreinitCodeGen.rangeSize); + s.write(codegenSize); + s.writeNullableData(coreinitCodeGen.cacheStateCopy, codegenSize); + } + + void CodeGen_Restore(MemStreamReader& s) + { + s.readSection("coreinit_CodeGen"); + s.readBool(coreinitCodeGen.rangeIsAllocated); + s.read(coreinitCodeGen.rangeStart); + s.read(coreinitCodeGen.rangeSize); + cemu_assert(s.read() == codegenSize); + s.readNullableData(coreinitCodeGen.cacheStateCopy, codegenSize); + } + void InitializeCodeGen() { cafeExportRegister("coreinit", OSGetCodegenVirtAddrRange, LogType::Placeholder); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.h b/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.h index ba41dd8794..ffc4ad6816 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_CodeGen.h @@ -6,5 +6,8 @@ namespace coreinit void codeGenHandleICBI(uint32 ea); bool codeGenShouldAvoid(); + void CodeGen_Save(MemStreamWriter& s); + void CodeGen_Restore(MemStreamReader& s); + void InitializeCodeGen(); } \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp index 546501b64d..05cf36ed70 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp @@ -131,6 +131,24 @@ namespace coreinit return 0; } + void DynLoad_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_DynLoad"); + s.write(_osDynLoadFuncAlloc); + s.write(_osDynLoadFuncFree); + s.write(_osDynLoadTLSFuncAlloc); + s.write(_osDynLoadTLSFuncFree); + } + + void DynLoad_Restore(MemStreamReader& s) + { + s.readSection("coreinit_DynLoad"); + s.read(_osDynLoadFuncAlloc); + s.read(_osDynLoadFuncFree); + s.read(_osDynLoadTLSFuncAlloc); + s.read(_osDynLoadTLSFuncFree); + } + void InitializeDynLoad() { cafeExportRegister("coreinit", OSDynLoad_SetAllocator, LogType::Placeholder); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h index 2a3172c7eb..bf8456639d 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h @@ -20,5 +20,8 @@ namespace coreinit void OSDynLoad_Release(uint32 moduleHandle); uint32 OSDynLoad_FindExport(uint32 moduleHandle, uint32 isData, const char* exportName, betype* addrOut); + void DynLoad_Save(MemStreamWriter& s); + void DynLoad_Restore(MemStreamReader& s); + void InitializeDynLoad(); } \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FG.cpp b/src/Cafe/OS/libs/coreinit/coreinit_FG.cpp index e22c3eb30c..60c1cc42b3 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FG.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_FG.cpp @@ -181,6 +181,22 @@ namespace coreinit osLib_returnFromFunction(hCPU, r ? 1 : 0); } + void FG_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_FG"); + s.writeMPTR(fgAddr); + s.writeMPTR(fgSaveAreaAddr); + s.writeData(&fgAreaEntries, sizeof(fgAreaEntries) * FG_BUCKET_AREA_COUNT); + } + + void FG_Restore(MemStreamReader& s) + { + s.readSection("coreinit_FG"); + s.readMPTR(fgAddr); + s.readMPTR(fgSaveAreaAddr); + s.readData(&fgAreaEntries, sizeof(fgAreaEntries) * FG_BUCKET_AREA_COUNT); + } + void InitializeFG() { osLib_addFunction("coreinit", "OSGetForegroundBucket", coreinitExport_OSGetForegroundBucket); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FG.h b/src/Cafe/OS/libs/coreinit/coreinit_FG.h index 0c2a3ee3ac..1d39f2729e 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FG.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_FG.h @@ -13,5 +13,8 @@ namespace coreinit void InitForegroundBucket(); + void FG_Save(MemStreamWriter& s); + void FG_Restore(MemStreamReader& s); + void InitializeFG(); } \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp index 0fc8912f29..2d202b1d3c 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp @@ -2644,6 +2644,32 @@ namespace coreinit return FSA_RESULT::OK; } + void FS_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_FS"); + s.writePTR(g_fsRegisteredClientBodies); + s.writeBool(_sdCard01Mounted); + s.writeBool(_mlc01Mounted); + s.writeMPTR(_tempFSSpace); + s.writePODVector(s_fsa_activeClients); + s.writeMPTR(s_fsaIpcPool); + s.writeMPTR(s_fsaIpcPoolBuffer); + s.writeMPTR(s_fsaIpcPoolBufferNumItems); + } + + void FS_Restore(MemStreamReader& s) + { + s.readSection("coreinit_FS"); + s.readPTR(g_fsRegisteredClientBodies); + s.readBool(_sdCard01Mounted); + s.readBool(_mlc01Mounted); + s.readMPTR(_tempFSSpace); + s.readPODVector(s_fsa_activeClients); + s.readMPTR(s_fsaIpcPool); + s.readMPTR(s_fsaIpcPoolBuffer); + s.readMPTR(s_fsaIpcPoolBufferNumItems); + } + void InitializeFS() { OSInitMutex(&s_fsGlobalMutex); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.h b/src/Cafe/OS/libs/coreinit/coreinit_FS.h index bf12e33c98..1e740147d2 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FS.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.h @@ -298,5 +298,8 @@ namespace coreinit FS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient); + void FS_Save(MemStreamWriter& s); + void FS_Restore(MemStreamReader& s); + void InitializeFS(); }; // namespace coreinit diff --git a/src/Cafe/OS/libs/coreinit/coreinit_GHS.cpp b/src/Cafe/OS/libs/coreinit/coreinit_GHS.cpp index 33c8eedc92..a9e9385b7d 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_GHS.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_GHS.cpp @@ -268,6 +268,24 @@ namespace coreinit return memory_getPointerFromVirtualOffset(_swapEndianU32(tlsBlock->addr) + _swapEndianU32(tlsIndex->ukn04)); } + void GHS_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_GHS"); + s.writeMPTR(g_ghs_data); + s.writeMPTR(_flockMutexArray); + s.writeData(reinterpret_cast(_flockMutexMask), sizeof(uint8) * GHS_FOPEN_MAX); + } + + void GHS_Restore(MemStreamReader& s) + { + s.readSection("coreinit_GHS"); + s.readMPTR(g_ghs_data); + s.readMPTR(_flockMutexArray); + uint8 _flockMutexMaskTmp[GHS_FOPEN_MAX] = { 0 }; + s.readData(_flockMutexMaskTmp, sizeof(uint8) * GHS_FOPEN_MAX); + memcpy(_flockMutexMask, reinterpret_cast(_flockMutexMaskTmp), sizeof(bool) * GHS_FOPEN_MAX); + } + void InitializeGHS() { cafeExportRegister("coreinit", __ghs_flock_create, LogType::Placeholder); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_GHS.h b/src/Cafe/OS/libs/coreinit/coreinit_GHS.h index 5f00073292..5b2fb1a9bd 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_GHS.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_GHS.h @@ -8,5 +8,8 @@ namespace coreinit void __gh_set_errno(sint32 errNo); sint32 __gh_get_errno(); + void GHS_Save(MemStreamWriter& s); + void GHS_Restore(MemStreamReader& s); + void InitializeGHS(); }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_IPC.cpp b/src/Cafe/OS/libs/coreinit/coreinit_IPC.cpp index 12d83afcac..076d428b42 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_IPC.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_IPC.cpp @@ -445,6 +445,30 @@ namespace coreinit return r; } + void IPC_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_IPC"); + s.writeMPTR(s_ipcResourceBuffers); + s.writeMPTR(s_ipcDriver); + s.writeMPTR(gIPCThread); + s.writeMPTR(_gIPCThreadStack); + s.writeMPTR(_gIPCThreadNameStorage); + s.writeMPTR(gIPCThreadMsgQueue); + s.writeMPTR(_gIPCThreadSemaphoreStorage); + } + + void IPC_Restore(MemStreamReader& s) + { + s.readSection("coreinit_IPC"); + s.readMPTR(s_ipcResourceBuffers); + s.readMPTR(s_ipcDriver); + s.readMPTR(gIPCThread); + s.readMPTR(_gIPCThreadStack); + s.readMPTR(_gIPCThreadNameStorage); + s.readMPTR(gIPCThreadMsgQueue); + s.readMPTR(_gIPCThreadSemaphoreStorage); + } + void InitializeIPC() { for (uint32 i = 0; i < Espresso::CORE_COUNT; i++) @@ -461,5 +485,4 @@ namespace coreinit cafeExportRegister("coreinit", IOS_Ioctlv, LogType::PPC_IPC); cafeExportRegister("coreinit", IOS_IoctlvAsync, LogType::PPC_IPC); } - }; diff --git a/src/Cafe/OS/libs/coreinit/coreinit_IPC.h b/src/Cafe/OS/libs/coreinit/coreinit_IPC.h index 362c472577..dc20dcfbbb 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_IPC.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_IPC.h @@ -12,5 +12,8 @@ namespace coreinit IOS_ERROR IOS_Ioctlv(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec); IOS_ERROR IOS_IoctlvAsync(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec, MEMPTR asyncResultFunc, MEMPTR asyncResultUserParam); + void IPC_Save(MemStreamWriter& s); + void IPC_Restore(MemStreamReader& s); + void InitializeIPC(); }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Init.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Init.cpp index 72f6ac117a..ee85ed4cae 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Init.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Init.cpp @@ -216,3 +216,21 @@ void coreinit_start(PPCInterpreter_t* hCPU) hCPU->gpr[3] = _coreinitInfo->argc; hCPU->instructionPointer = _coreinitTitleEntryPoint; } + +void coreinit_Init_Save(MemStreamWriter& s) +{ + s.writeSection("coreinit_Init"); + s.writeNullableData(_coreinitInfo, sizeof(coreinitInit_t)); + s.write(argStorageIndex); + s.writeMPTR(g_preinitUserParam); + s.write(_coreinitTitleEntryPoint); +} + +void coreinit_Init_Restore(MemStreamReader& s) +{ + s.readSection("coreinit_Init"); + s.readNullableData(_coreinitInfo, sizeof(coreinitInit_t)); + s.read(argStorageIndex); + s.readMPTR(g_preinitUserParam); + s.read(_coreinitTitleEntryPoint); +} \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp index a051fce1d0..a51dccf4d5 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp @@ -271,6 +271,22 @@ namespace coreinit osLib_returnFromFunction(hCPU, 0); } + void LockedCache_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_LockedCache"); + s.writeData(lcCacheMask, sizeof(uint8) * PPC_CORE_COUNT * (LC_LOCKED_CACHE_SIZE + LC_LOCKED_CACHE_GRANULARITY - 1) / LC_LOCKED_CACHE_GRANULARITY); + s.writeData(lcAllocatedBlocks, sizeof(uint32) * PPC_CORE_COUNT); + s.write(_lcDisableErrorCounter); + } + + void LockedCache_Restore(MemStreamReader& s) + { + s.readSection("coreinit_LockedCache"); + s.readData(lcCacheMask, sizeof(uint8) * PPC_CORE_COUNT * (LC_LOCKED_CACHE_SIZE + LC_LOCKED_CACHE_GRANULARITY - 1) / LC_LOCKED_CACHE_GRANULARITY); + s.readData(lcAllocatedBlocks, sizeof(uint32) * PPC_CORE_COUNT); + s.read(_lcDisableErrorCounter); + } + void InitializeLC() { for (sint32 f = 0; f < PPC_CORE_COUNT; f++) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.h b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.h index d2fbcbdfd6..3ef219932c 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.h @@ -2,5 +2,8 @@ namespace coreinit { + void LockedCache_Save(MemStreamWriter& s); + void LockedCache_Restore(MemStreamReader& s); + void InitializeLC(); } \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MEM.cpp b/src/Cafe/OS/libs/coreinit/coreinit_MEM.cpp index 83658f3c8b..30ca113552 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MEM.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_MEM.cpp @@ -630,6 +630,42 @@ namespace coreinit memset(&g_list3, 0, sizeof(g_list3)); } + void MEM_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_MEM"); + s.write(sysAreaAllocatorOffset); + s.write(g_heapTableCount); + s.writeData(g_heapTable, sizeof(MEMHeapBase) * MEM_MAX_HEAP_TABLE); + s.writeBool(g_slockInitialized); + s.writeBool(g_listsInitialized); + s.writeData(&g_list1, sizeof(MEMList)); + s.writeData(&g_list2, sizeof(MEMList)); + s.writeData(&g_list3, sizeof(MEMList)); + s.writeData(&gHeapFillValues, sizeof(uint32) * 3); + s.writeMPTR(gHeapGlobalLock); + s.writeData(&gDefaultHeap, sizeof(MEMHeapBase)); + s.writeData(&sHeapBaseHandle, sizeof(MEMHeapBase) * 9); + s.writeMPTR(gDefaultHeapAllocator); + } + + void MEM_Restore(MemStreamReader& s) + { + s.readSection("coreinit_MEM"); + s.read(sysAreaAllocatorOffset); + s.read(g_heapTableCount); + s.readData(g_heapTable, sizeof(MEMHeapBase) * MEM_MAX_HEAP_TABLE); + s.readBool(g_slockInitialized); + s.readBool(g_listsInitialized); + s.readData(&g_list1, sizeof(MEMList)); + s.readData(&g_list2, sizeof(MEMList)); + s.readData(&g_list3, sizeof(MEMList)); + s.readData(&gHeapFillValues, sizeof(uint32) * 3); + s.readMPTR(gHeapGlobalLock); + s.readData(&gDefaultHeap, sizeof(MEMHeapBase)); + s.readData(&sHeapBaseHandle, sizeof(MEMHeapBase) * 9); + s.readMPTR(gDefaultHeapAllocator); + } + void InitializeMEM() { MEMResetToDefaultState(); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MEM.h b/src/Cafe/OS/libs/coreinit/coreinit_MEM.h index 7e5831951e..7420fe5bc4 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MEM.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_MEM.h @@ -179,5 +179,8 @@ namespace coreinit void InitializeMEMUnitHeap(); + void MEM_Save(MemStreamWriter& s); + void MEM_Restore(MemStreamReader& s); + void InitializeMEM(); } diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp b/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp index d32a105cee..cfce570fa3 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp @@ -16,6 +16,8 @@ namespace coreinit struct OSVirtMemoryEntry { + OSVirtMemoryEntry() : virtualAddress(0), size(0), alignment(0) {}; + OSVirtMemoryEntry(MPTR virtualAddress, uint32 size, uint32 alignment) : virtualAddress(virtualAddress), size(size), alignment(alignment) {}; MPTR virtualAddress; @@ -151,6 +153,30 @@ namespace coreinit return 1; } + void MemoryMapping_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_MemoryMapping"); + s.write(s_allocatedVirtMemory.size()); + for (auto i : s_allocatedVirtMemory) + { + s.write(i.virtualAddress); + s.write(i.size); + s.write(i.alignment); + } + } + + void MemoryMapping_Restore(MemStreamReader& s) + { + s.readSection("coreinit_MemoryMapping"); + uint32 s_allocatedVirtMemorySize = s.read(); + s_allocatedVirtMemory.clear(); + s_allocatedVirtMemory.reserve(s_allocatedVirtMemorySize); + for (sint32 i = 0; i < s_allocatedVirtMemorySize; i++) + { + s_allocatedVirtMemory.emplace_back(s.read(), s.read(), s.read()); + } + } + void InitializeMemoryMapping() { s_allocatedVirtMemory.clear(); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.h b/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.h index f51d9a6a67..a884fa3f8b 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.h @@ -1,5 +1,8 @@ namespace coreinit { + void MemoryMapping_Save(MemStreamWriter& s); + void MemoryMapping_Restore(MemStreamReader& s); + void InitializeMemoryMapping(); } diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.cpp b/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.cpp index cbcfa4d156..fe87cd56d0 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.cpp @@ -124,6 +124,20 @@ namespace coreinit return g_systemMessageQueue.GetPtr(); } + void MessageQueue_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_MessageQueue"); + s.writeMPTR(g_systemMessageQueue); + s.writeMPTR(_systemMessageQueueArray); + } + + void MessageQueue_Restore(MemStreamReader& s) + { + s.readSection("coreinit_MessageQueue"); + s.readMPTR(g_systemMessageQueue); + s.readMPTR(_systemMessageQueueArray); + } + void InitializeMessageQueue() { OSInitMessageQueue(g_systemMessageQueue.GetPtr(), _systemMessageQueueArray.GetPtr(), _systemMessageQueueArray.GetCount()); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.h b/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.h index 35fdc3e724..233d6a1182 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.h @@ -47,5 +47,8 @@ namespace coreinit OSMessageQueue* OSGetSystemMessageQueue(); + void MessageQueue_Save(MemStreamWriter& s); + void MessageQueue_Restore(MemStreamReader& s); + void InitializeMessageQueue(); }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.cpp b/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.cpp index 5e5d88520c..85978484ee 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.cpp @@ -25,6 +25,17 @@ namespace coreinit *areaSize = MEMORY_OVERLAY_AREA_SIZE; } + void OverlayArena_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_OverlayArena"); + s.writeBool(g_coreinitOverlayArena.isEnabled); + } + void OverlayArena_Restore(MemStreamReader& s) + { + s.readSection("coreinit_OverlayArena"); + s.readBool(g_coreinitOverlayArena.isEnabled); + } + void InitializeOverlayArena() { cafeExportRegister("coreinit", OSIsEnabledOverlayArena, LogType::Placeholder); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.h b/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.h index d9d5868fbb..70657fc9a5 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.h @@ -1,4 +1,7 @@ namespace coreinit { + void OverlayArena_Save(MemStreamWriter& s); + void OverlayArena_Restore(MemStreamReader& s); + void InitializeOverlayArena(); }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp index e81cc57708..7354803b38 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp @@ -612,6 +612,18 @@ namespace coreinit OSWakeupThread(&fastCond->threadQueue); } + void Synchronization_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_Synchronization"); + s.writeMPTR(g_rendezvousEvent); + } + + void Synchronization_Restore(MemStreamReader& s) + { + s.readSection("coreinit_Synchronization"); + s.readMPTR(g_rendezvousEvent); + } + /************* init ************/ void InitializeConcurrency() diff --git a/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.cpp b/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.cpp index 2f819c5000..c0991e7efa 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.cpp @@ -29,6 +29,22 @@ namespace coreinit _sysHeapFreeCounter = 0; } + void SysHeap_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_SysHeap"); + s.writePTR(_sysHeapHandle); + s.write(_sysHeapAllocCounter); + s.write(_sysHeapFreeCounter); + } + + void SysHeap_Restore(MemStreamReader& s) + { + s.readSection("coreinit_SysHeap"); + s.readPTR(_sysHeapHandle); + s.read(_sysHeapAllocCounter); + s.read(_sysHeapFreeCounter); + } + void InitializeSysHeap() { cafeExportRegister("h264", OSAllocFromSystem, LogType::CoreinitMem); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.h b/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.h index ad1157547e..8010056104 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_SysHeap.h @@ -7,5 +7,8 @@ namespace coreinit void* OSAllocFromSystem(uint32 size, uint32 alignment); void OSFreeToSystem(void* ptr); + void SysHeap_Save(MemStreamWriter& s); + void SysHeap_Restore(MemStreamReader& s); + void InitializeSysHeap(); } \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.cpp b/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.cpp index 83925acdfb..638d4093e2 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.cpp @@ -10,6 +10,18 @@ namespace coreinit return *g_system_info.GetPtr(); } + void SystemInfo_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_SysInfo"); + s.writeMPTR(g_system_info); + } + + void SystemInfo_Restore(MemStreamReader& s) + { + s.readSection("coreinit_SysInfo"); + s.readMPTR(g_system_info); + } + void InitializeSystemInfo() { cemu_assert(ppcCyclesSince2000 != 0); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.h b/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.h index b2c50069c2..478dd4f847 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.h @@ -15,7 +15,10 @@ namespace coreinit static_assert(sizeof(OSSystemInfo) == 0x20); const OSSystemInfo& OSGetSystemInfo(); - + + void SystemInfo_Save(MemStreamWriter& s); + void SystemInfo_Restore(MemStreamReader& s); + void InitializeSystemInfo(); }; diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp index 870d1850a7..8c39c1b3c7 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp @@ -14,6 +14,7 @@ #include "util/Fiber/Fiber.h" #include "util/helpers/helpers.h" +#include "Common/FileStream.h" SlimRWLock srwlock_activeThreadList; @@ -1551,6 +1552,133 @@ namespace coreinit } } + void DumpActiveThreads(std::string v) + { + for (auto& thr : activeThread) + { + if (thr != MPTR_NULL) + { + auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(thr); + MemStreamWriter writer(0); + writer.writeData(ptr, sizeof(OSThread_t)); + FileStream* stream = FileStream::createFile(std::to_string(thr) + "_" + v + ".bin"); + stream->writeData(writer.getResult().data(), writer.getResult().size_bytes()); + delete stream; + } + } + } + + void Thread_Save(MemStreamWriter& s) + { + s.writeSection("coreinit_Thread"); + + s.writeAtomic(sSchedulerActive); + s.writeMPTR(g_activeThreadQueue); + s.writeMPTR(g_coreRunQueue); + + s.write(activeThreadCount); + for (sint32 i = 0; i < activeThreadCount; i++) + { + s.write(activeThread[i]); + auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(activeThread[i]); + //s.write((uint8)ptr->state.value()); + } + for (sint32 i = 0; i < PPC_CORE_COUNT; i++) + { + s.writePTR(__currentCoreThread[i]); + s.write(s_lehmer_lcg[i]); + s.writeMPTR(s_terminatorThreads[i].terminatorThread); + s.writeMPTR(s_terminatorThreads[i].threadStack); + s.writeMPTR(s_terminatorThreads[i].threadName); + s.writeMPTR(s_terminatorThreads[i].semaphoreQueuedDeallocators); + s.writeMPTR(_defaultThreadName[i]); + } + s.writeMPTR(s_defaultThreads); + s.writeMPTR(s_stack); + + DumpActiveThreads("save"); + } + + void Thread_Restore(MemStreamReader& s) + { + s.readSection("coreinit_Thread"); + + s.readAtomic(sSchedulerActive); + s.readMPTR(g_activeThreadQueue); + s.readMPTR(g_coreRunQueue); + + bool recreate = false; + + sint32 prevActiveThreadCount = s.read(); + for (sint32 i = 0; i < prevActiveThreadCount; i++) + { + MPTR threadMPTR = s.read(); + if (recreate) + { + auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(threadMPTR); + + __OSLockScheduler(); + __OSActivateThread(ptr); + __OSUnlockScheduler(); + //ptr->state = betype((OSThread_t::THREAD_STATE)s.read()); + } + else + { + activeThreadCount = prevActiveThreadCount; + activeThread[i] = threadMPTR; + } + } + for (sint32 i = 0; i < PPC_CORE_COUNT; i++) + { + s.readPTR(__currentCoreThread[i]); + s.read(s_lehmer_lcg[i]); + s.readMPTR(s_terminatorThreads[i].terminatorThread); + s.readMPTR(s_terminatorThreads[i].threadStack); + s.readMPTR(s_terminatorThreads[i].threadName); + s.readMPTR(s_terminatorThreads[i].semaphoreQueuedDeallocators); + s.readMPTR(_defaultThreadName[i]); + } + s.readMPTR(s_defaultThreads); + s.readMPTR(s_stack); + + DumpActiveThreads("restore"); + } + + void SuspendActiveThreads() + { + + for (auto& thr : activeThread) + { + if (thr != MPTR_NULL) + { + auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(thr); + cemuLog_log(LogType::SaveStates, "Before State: {}", ptr->state.value()); + cemuLog_log(LogType::SaveStates, "Before SusCnt: {}", ptr->suspendCounter); + OSSuspendThread(ptr); + cemuLog_log(LogType::SaveStates, "After State: {}", ptr->state.value()); + cemuLog_log(LogType::SaveStates, "After SusCnt: {}", ptr->suspendCounter); + } + } + } + + void ResumeActiveThreads() + { + for (auto& thr : activeThread) + { + if (thr != MPTR_NULL) + { + auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(thr); + if (s_threadToFiber.find(ptr) == s_threadToFiber.end()) + { + __OSLockScheduler(); + __OSCreateHostThread(ptr); + __OSUnlockScheduler(); + } + OSResumeThread(ptr); + } + } + } + void InitializeThread() { cafeExportRegister("coreinit", OSCreateThreadType, LogType::CoreinitThread); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h index 1a93022b3d..b64a2cf249 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h @@ -503,7 +503,16 @@ static_assert(sizeof(OSThread_t) == 0x6A0); namespace coreinit { + void Thread_Save(MemStreamWriter& s); + void Thread_Restore(MemStreamReader& s); + void SuspendActiveThreads(); + void ResumeActiveThreads(); + void InitializeThread(); + + void Synchronization_Save(MemStreamWriter& s); + void Synchronization_Restore(MemStreamReader& s); + void InitializeConcurrency(); bool __CemuIsMulticoreMode(); diff --git a/src/Cafe/OS/libs/dmae/dmae.cpp b/src/Cafe/OS/libs/dmae/dmae.cpp index 7c51378474..848d43bbff 100644 --- a/src/Cafe/OS/libs/dmae/dmae.cpp +++ b/src/Cafe/OS/libs/dmae/dmae.cpp @@ -108,6 +108,17 @@ void dmaeExport_DMAEGetRetiredTimeStamp(PPCInterpreter_t* hCPU) osLib_returnFromFunction64(hCPU, dmaeRetiredTimestamp); } +void dmae_save(MemStreamWriter& s) +{ + s.writeSection("dmae"); + s.write(dmaeRetiredTimestamp); +} + +void dmae_restore(MemStreamReader& s) +{ + s.readSection("dmae"); + s.read(dmaeRetiredTimestamp); +} void dmae_load() { diff --git a/src/Cafe/OS/libs/dmae/dmae.h b/src/Cafe/OS/libs/dmae/dmae.h index 26d371c9ca..74acef4cdc 100644 --- a/src/Cafe/OS/libs/dmae/dmae.h +++ b/src/Cafe/OS/libs/dmae/dmae.h @@ -1 +1,4 @@ +void dmae_save(MemStreamWriter& s); +void dmae_restore(MemStreamReader& s); + void dmae_load(); \ No newline at end of file diff --git a/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp b/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp index a992665ce2..f056197910 100644 --- a/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp +++ b/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp @@ -1503,6 +1503,29 @@ CURLcode curl_global_init_mem(uint32 flags, MEMPTR malloc_ return result; } +void save(MemStreamWriter& s) +{ + s.writeSection("nlibcurl"); + s.write(g_nlibcurl.initialized); + s.writeMPTR(g_nlibcurl.proxyConfig); + s.writeMPTR(g_nlibcurl.malloc); + s.writeMPTR(g_nlibcurl.free); + s.writeMPTR(g_nlibcurl.realloc); + s.writeMPTR(g_nlibcurl.strdup); + s.writeMPTR(g_nlibcurl.calloc); +} +void restore(MemStreamReader& s) +{ + s.readSection("nlibcurl"); + s.read(g_nlibcurl.initialized); + s.readMPTR(g_nlibcurl.proxyConfig); + s.readMPTR(g_nlibcurl.malloc); + s.readMPTR(g_nlibcurl.free); + s.readMPTR(g_nlibcurl.realloc); + s.readMPTR(g_nlibcurl.strdup); + s.readMPTR(g_nlibcurl.calloc); +} + void load() { cafeExportRegister("nlibcurl", curl_global_init_mem, LogType::nlibcurl); diff --git a/src/Cafe/OS/libs/nlibcurl/nlibcurl.h b/src/Cafe/OS/libs/nlibcurl/nlibcurl.h index 5075a79cb4..273b5a6b2c 100644 --- a/src/Cafe/OS/libs/nlibcurl/nlibcurl.h +++ b/src/Cafe/OS/libs/nlibcurl/nlibcurl.h @@ -2,5 +2,8 @@ namespace nlibcurl { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); } \ No newline at end of file diff --git a/src/Cafe/OS/libs/nn_acp/nn_acp.cpp b/src/Cafe/OS/libs/nn_acp/nn_acp.cpp index 9cde021359..a41c548351 100644 --- a/src/Cafe/OS/libs/nn_acp/nn_acp.cpp +++ b/src/Cafe/OS/libs/nn_acp/nn_acp.cpp @@ -335,6 +335,18 @@ namespace acp osLib_returnFromFunction(hCPU, 0); } + void save(MemStreamWriter& s) + { + s.writeSection("nn_acp"); + s.writeBool(sSaveDirMounted); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_acp"); + s.readBool(sSaveDirMounted); + } + void load() { cafeExportRegister("nn_acp", ACPCheckApplicationDeviceEmulation, LogType::Placeholder); diff --git a/src/Cafe/OS/libs/nn_acp/nn_acp.h b/src/Cafe/OS/libs/nn_acp/nn_acp.h index 9890a6dfe8..b1126256a3 100644 --- a/src/Cafe/OS/libs/nn_acp/nn_acp.h +++ b/src/Cafe/OS/libs/nn_acp/nn_acp.h @@ -18,6 +18,9 @@ namespace acp ACPStatus ACPCreateSaveDir(uint32 persistentId, iosu::acp::ACPDeviceType type); ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, iosu::acp::ACPDeviceType deviceType); + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); } } diff --git a/src/Cafe/OS/libs/nn_act/nn_act.cpp b/src/Cafe/OS/libs/nn_act/nn_act.cpp index f9e7435593..f39698e1cf 100644 --- a/src/Cafe/OS/libs/nn_act/nn_act.cpp +++ b/src/Cafe/OS/libs/nn_act/nn_act.cpp @@ -683,6 +683,19 @@ void nnActExport_AcquirePrincipalIdByAccountId(PPCInterpreter_t* hCPU) osLib_returnFromFunction(hCPU, result); } +void nnAct_save(MemStreamWriter& s) +{ + s.writeSection("nn_act"); + s.write(nn::act::g_initializeCount); + s.write((uint32)g_isParentalControlCheckEnabled); +} +void nnAct_restore(MemStreamReader& s) +{ + s.readSection("nn_act"); + s.read(nn::act::g_initializeCount); + g_isParentalControlCheckEnabled = s.read(); +} + // register account functions void nnAct_load() { diff --git a/src/Cafe/OS/libs/nn_act/nn_act.h b/src/Cafe/OS/libs/nn_act/nn_act.h index 6b0a12368a..e0d0f9d616 100644 --- a/src/Cafe/OS/libs/nn_act/nn_act.h +++ b/src/Cafe/OS/libs/nn_act/nn_act.h @@ -33,4 +33,7 @@ namespace act } } +void nnAct_save(MemStreamWriter& s); +void nnAct_restore(MemStreamReader& s); + void nnAct_load(); \ No newline at end of file diff --git a/src/Cafe/OS/libs/nn_aoc/nn_aoc.cpp b/src/Cafe/OS/libs/nn_aoc/nn_aoc.cpp index aa81fa5889..dfd4df2ff9 100644 --- a/src/Cafe/OS/libs/nn_aoc/nn_aoc.cpp +++ b/src/Cafe/OS/libs/nn_aoc/nn_aoc.cpp @@ -149,6 +149,30 @@ namespace nn return AOC_RESULT::ERROR_OK; } + void save(MemStreamWriter& s) + { + s.writeSection("nn_aoc"); + s.write(sAocCache.size()); + for (auto i : sAocCache) + { + s.write(i.aocTitleId); + } + s.writeBool(sAocCacheGenerated); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_aoc"); + uint32 sAocCacheSize = s.read(); + sAocCache.clear(); + sAocCache.reserve(sAocCacheSize); + for (sint32 i = 0; i < sAocCacheSize; i++) + { + sAocCache.emplace_back(s.read()); + } + s.readBool(sAocCacheGenerated); + } + void Initialize() { cafeExportRegister("nn_aoc", AOC_CalculateWorkBufferSize, LogType::NN_AOC); diff --git a/src/Cafe/OS/libs/nn_aoc/nn_aoc.h b/src/Cafe/OS/libs/nn_aoc/nn_aoc.h index 3853c07529..9a08667dfe 100644 --- a/src/Cafe/OS/libs/nn_aoc/nn_aoc.h +++ b/src/Cafe/OS/libs/nn_aoc/nn_aoc.h @@ -2,6 +2,9 @@ namespace nn { namespace aoc { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void Initialize(); } } \ No newline at end of file diff --git a/src/Cafe/OS/libs/nn_boss/nn_boss.cpp b/src/Cafe/OS/libs/nn_boss/nn_boss.cpp index 2a05fa7a48..dde7f5f530 100644 --- a/src/Cafe/OS/libs/nn_boss/nn_boss.cpp +++ b/src/Cafe/OS/libs/nn_boss/nn_boss.cpp @@ -1617,6 +1617,22 @@ bossBufferVector->buffer = (uint8*)bossRequest; } } +void nnBoss_save(MemStreamWriter& s) +{ + s.writeSection("nn_boss"); + s.writeMPTR(nn::boss::g_mutex); + s.write(nn::boss::g_initCounter); + s.writeBool(nn::boss::g_isInitialized); +} + +void nnBoss_restore(MemStreamReader& s) +{ + s.readSection("nn_boss"); + s.readMPTR(nn::boss::g_mutex); + s.read(nn::boss::g_initCounter); + s.readBool(nn::boss::g_isInitialized); +} + void nnBoss_load() { OSInitMutexEx(&nn::boss::g_mutex, nullptr); diff --git a/src/Cafe/OS/libs/nn_boss/nn_boss.h b/src/Cafe/OS/libs/nn_boss/nn_boss.h index f9a434a01d..ca0ee066a0 100644 --- a/src/Cafe/OS/libs/nn_boss/nn_boss.h +++ b/src/Cafe/OS/libs/nn_boss/nn_boss.h @@ -1 +1,4 @@ +void nnBoss_save(MemStreamWriter& s); +void nnBoss_restore(MemStreamReader& s); + void nnBoss_load(); \ No newline at end of file diff --git a/src/Cafe/OS/libs/nn_fp/nn_fp.cpp b/src/Cafe/OS/libs/nn_fp/nn_fp.cpp index 86ca47080b..81a41aac48 100644 --- a/src/Cafe/OS/libs/nn_fp/nn_fp.cpp +++ b/src/Cafe/OS/libs/nn_fp/nn_fp.cpp @@ -758,6 +758,20 @@ namespace nn return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } + void save(MemStreamWriter& s) + { + s.writeSection("nn_fp"); + s.writeBool(g_fp.isAdminMode); + s.writeBool(g_fp.isInitialized); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_fp"); + s.readBool(g_fp.isAdminMode); + s.readBool(g_fp.isInitialized); + } + void load() { g_fp.initCounter = 0; diff --git a/src/Cafe/OS/libs/nn_fp/nn_fp.h b/src/Cafe/OS/libs/nn_fp/nn_fp.h index daab14a0d9..f3529c8cbf 100644 --- a/src/Cafe/OS/libs/nn_fp/nn_fp.h +++ b/src/Cafe/OS/libs/nn_fp/nn_fp.h @@ -3,6 +3,9 @@ namespace nn { namespace fp { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); } } \ No newline at end of file diff --git a/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp b/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp index 5a69b787ec..b47fbf76f7 100644 --- a/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp +++ b/src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp @@ -74,6 +74,20 @@ namespace nn return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NDM, 0); } + void save(MemStreamWriter& s) + { + s.writeSection("nn_ndm"); + s.writeData(s_daemonStatus, sizeof(DAEMON_STATUS) * NUM_DAEMONS); + s.write(s_initializeRefCount); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_ndm"); + s.readData(s_daemonStatus, sizeof(DAEMON_STATUS) * NUM_DAEMONS); + s.read(s_initializeRefCount); + } + void load() { for(size_t i=0; i(sizeof(AmiiboRawNFCData)); + s.writeData(&nfp_data.amiiboNFCData, sizeof(AmiiboRawNFCData)); + s.write(sizeof(AmiiboInternal)); + s.writeData(&nfp_data.amiiboInternal, sizeof(AmiiboInternal)); + s.write(sizeof(AmiiboProcessedData)); + s.writeData(&nfp_data.amiiboProcessedData, sizeof(AmiiboProcessedData)); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_nfp"); + s.readBool(nfp_data.nfpIsInitialized); + s.read(nfp_data.activateEvent); + s.read(nfp_data.deactivateEvent); + s.readBool(nfp_data.isDetecting); + s.readBool(nfp_data.isMounted); + s.readBool(nfp_data.isReadOnly); + s.readBool(nfp_data.hasOpenApplicationArea); + s.readBool(nfp_data.hasActiveAmiibo); + + s.readBool(nfp_data.hasInvalidHMAC); + s.read(nfp_data.amiiboTouchTime); + cemu_assert(s.read() == sizeof(AmiiboRawNFCData)); + s.readData(&nfp_data.amiiboNFCData, sizeof(AmiiboRawNFCData)); + cemu_assert(s.read() == sizeof(AmiiboInternal)); + s.readData(&nfp_data.amiiboInternal, sizeof(AmiiboInternal)); + cemu_assert(s.read() == sizeof(AmiiboProcessedData)); + s.readData(&nfp_data.amiiboProcessedData, sizeof(AmiiboProcessedData)); + } + void load() { nnNfp_load(); // legacy interface, update these to use cafeExportRegister / cafeExportRegisterFunc diff --git a/src/Cafe/OS/libs/nn_nfp/nn_nfp.h b/src/Cafe/OS/libs/nn_nfp/nn_nfp.h index 25b36cc9e4..cd8b5270e0 100644 --- a/src/Cafe/OS/libs/nn_nfp/nn_nfp.h +++ b/src/Cafe/OS/libs/nn_nfp/nn_nfp.h @@ -4,6 +4,9 @@ namespace nn::nfp { uint32 NFCGetTagInfo(uint32 index, uint32 timeout, MPTR functionPtr, void* userParam); + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); } diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv.cpp index 1916a18dbd..5d993fdb20 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv.cpp @@ -111,6 +111,44 @@ namespace nn static_assert(GetErrorCodeImpl(0xa119c600) == 1155004); + void save(MemStreamWriter& s) + { + s.writeSection("nn_olv"); + s.writeMPTR(s_OlvReleaseBgThread); + s.writeMPTR(s_OlvReleaseBgThreadStack); + s.writeMPTR(s_OlvReleaseBgThreadName); + s.write(sizeof(ParamPackStorage)); + s.writeData(&g_ParamPack, sizeof(ParamPackStorage)); + s.write(sizeof(DiscoveryResultStorage)); + s.writeData(&g_DiscoveryResults, sizeof(DiscoveryResultStorage)); + s.write(g_ReportTypes); + s.writeBool(g_IsInitialized); + s.writeBool(g_IsOnlineMode); + s.writeBool(g_IsOfflineDBMode); + s.writeBool(OfflineDB_Initialized()); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_olv"); + s.readMPTR(s_OlvReleaseBgThread); + s.readMPTR(s_OlvReleaseBgThreadStack); + s.readMPTR(s_OlvReleaseBgThreadName); + cemu_assert(s.read() == sizeof(ParamPackStorage)); + s.readData(&g_ParamPack, sizeof(ParamPackStorage)); + cemu_assert(s.read() == sizeof(DiscoveryResultStorage)); + s.readData(&g_DiscoveryResults, sizeof(DiscoveryResultStorage)); + s.read(g_ReportTypes); + s.readBool(g_IsInitialized); + s.readBool(g_IsOnlineMode); + s.readBool(g_IsOfflineDBMode); + if (s.readBool()) + { + OfflineDB_Shutdown(); + OfflineDB_LazyInit(); + } + } + void load() { g_ReportTypes = 0; diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv.h b/src/Cafe/OS/libs/nn_olv/nn_olv.h index 52474b4916..6e04dd51a9 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv.h +++ b/src/Cafe/OS/libs/nn_olv/nn_olv.h @@ -18,6 +18,9 @@ namespace nn sint32 GetOlvAccessKey(uint32_t* pOutKey); + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); void unload(); } diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp index c87cbd3988..dc39400eb1 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp @@ -17,6 +17,11 @@ namespace nn bool g_offlineDBInitialized = false; ZArchiveReader* g_offlineDBArchive{nullptr}; + bool OfflineDB_Initialized() + { + return g_offlineDBInitialized; + } + void OfflineDB_LazyInit() { std::scoped_lock _l(g_offlineDBMutex); diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.h b/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.h index ed7904799f..a146db9833 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.h +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.h @@ -6,7 +6,9 @@ namespace nn { namespace olv { - void OfflineDB_Init(); + bool OfflineDB_Initialized(); + + void OfflineDB_LazyInit(); void OfflineDB_Shutdown(); nnResult OfflineDB_DownloadPostDataListParam_DownloadPostDataList(DownloadedTopicData* downloadedTopicData, DownloadedPostData* downloadedPostData, uint32be* postCountOut, uint32 maxCount, DownloadPostDataListParam* param); diff --git a/src/Cafe/OS/libs/nn_save/nn_save.cpp b/src/Cafe/OS/libs/nn_save/nn_save.cpp index 31f8ac8e1e..14512ea7b4 100644 --- a/src/Cafe/OS/libs/nn_save/nn_save.cpp +++ b/src/Cafe/OS/libs/nn_save/nn_save.cpp @@ -840,6 +840,18 @@ namespace save return asyncData->GetResult(); } + void save(MemStreamWriter& s) + { + s.writeSection("nn_save"); + s.writeMPTR(g_nn_save); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_save"); + s.readMPTR(g_nn_save); + } + void load() { cafeExportRegister("nn_save", SAVEInit, LogType::Save); diff --git a/src/Cafe/OS/libs/nn_save/nn_save.h b/src/Cafe/OS/libs/nn_save/nn_save.h index 5c9b3b52e2..a8824a5a6d 100644 --- a/src/Cafe/OS/libs/nn_save/nn_save.h +++ b/src/Cafe/OS/libs/nn_save/nn_save.h @@ -4,6 +4,9 @@ namespace nn { namespace save { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); void ResetToDefaultState(); diff --git a/src/Cafe/OS/libs/nn_temp/nn_temp.cpp b/src/Cafe/OS/libs/nn_temp/nn_temp.cpp index aaddabd2b0..be0d7fe3c7 100644 --- a/src/Cafe/OS/libs/nn_temp/nn_temp.cpp +++ b/src/Cafe/OS/libs/nn_temp/nn_temp.cpp @@ -16,6 +16,18 @@ namespace nn::temp osLib_returnFromFunction(hCPU, 0); } + void save(MemStreamWriter& s) + { + s.writeSection("nn_temp"); + s.write(tempIdGenerator); + } + + void restore(MemStreamReader& s) + { + s.readSection("nn_temp"); + s.read(tempIdGenerator); + } + void Initialize() { osLib_addFunction("nn_temp", "TEMPCreateAndInitTempDir", nnTempExport_TEMPCreateAndInitTempDir); diff --git a/src/Cafe/OS/libs/nn_temp/nn_temp.h b/src/Cafe/OS/libs/nn_temp/nn_temp.h index da2b74c070..a185edcf97 100644 --- a/src/Cafe/OS/libs/nn_temp/nn_temp.h +++ b/src/Cafe/OS/libs/nn_temp/nn_temp.h @@ -2,5 +2,8 @@ namespace nn::temp { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void Initialize(); }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/nn_uds/nn_uds.cpp b/src/Cafe/OS/libs/nn_uds/nn_uds.cpp index 08f67c7dce..6b7ad8415e 100644 --- a/src/Cafe/OS/libs/nn_uds/nn_uds.cpp +++ b/src/Cafe/OS/libs/nn_uds/nn_uds.cpp @@ -15,6 +15,18 @@ void nnUdsExport___sti___11_uds_Api_cpp_f5d9abb2(PPCInterpreter_t* hCPU) osLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(udsWorkspace)); } +void nnUds_save(MemStreamWriter& s) +{ + s.writeSection("nn_uds"); + s.writeNullableData(udsWorkspace, sizeof(udsWorkspace_t)); +} + +void nnUds_restore(MemStreamReader& s) +{ + s.readSection("nn_uds"); + s.readNullableData(udsWorkspace, sizeof(udsWorkspace_t)); +} + /* * Load UDS functions */ diff --git a/src/Cafe/OS/libs/nn_uds/nn_uds.h b/src/Cafe/OS/libs/nn_uds/nn_uds.h index 7177ca4b85..9762bc8457 100644 --- a/src/Cafe/OS/libs/nn_uds/nn_uds.h +++ b/src/Cafe/OS/libs/nn_uds/nn_uds.h @@ -1 +1,4 @@ +void nnUds_save(MemStreamWriter& s); +void nnUds_restore(MemStreamReader& s); + void nnUds_load(); \ No newline at end of file diff --git a/src/Cafe/OS/libs/nsyshid/nsyshid.cpp b/src/Cafe/OS/libs/nsyshid/nsyshid.cpp index 2fe6da0716..e893a75c0b 100644 --- a/src/Cafe/OS/libs/nsyshid/nsyshid.cpp +++ b/src/Cafe/OS/libs/nsyshid/nsyshid.cpp @@ -944,6 +944,28 @@ namespace nsyshid this->m_hid = hid; } + void save(MemStreamWriter& s) + { + s.writeSection("nsyshid"); + s.writePTR(firstDevice); + s.writeNullableData(firstHIDClient, sizeof(HIDClient_t)); + s.write(_lastGeneratedHidHandle); + s.writeMPTR(_devicePool); + s.write(_devicePoolMask.count()); + } + + void restore(MemStreamReader& s) + { + s.readSection("nsyshid"); + s.readPTR(firstDevice); + s.readNullableData(firstHIDClient, sizeof(HIDClient_t)); + s.read(_lastGeneratedHidHandle); + s.readMPTR(_devicePool); + _devicePoolMask.reset(); + for (size_t i = 0; i < s.read(); i++) + _devicePoolMask.set(i); + } + void load() { osLib_addFunction("nsyshid", "HIDAddClient", export_HIDAddClient); diff --git a/src/Cafe/OS/libs/nsyshid/nsyshid.h b/src/Cafe/OS/libs/nsyshid/nsyshid.h index 1478adf96e..5fef79daa4 100644 --- a/src/Cafe/OS/libs/nsyshid/nsyshid.h +++ b/src/Cafe/OS/libs/nsyshid/nsyshid.h @@ -8,5 +8,8 @@ namespace nsyshid void DetachBackend(const std::shared_ptr& backend); + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void load(); } // namespace nsyshid diff --git a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp index c83915db5e..deffb16e32 100644 --- a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp +++ b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp @@ -2223,6 +2223,83 @@ namespace nsysnet } } +template<> +void MemStreamWriter::write(const nsysnet::NSSLInternalState_t& v) +{ + writeBool(v.destroyed); + write(v.sslVersion); + write(v.clientPKI); + + write(v.serverPKIs.size()); + for (auto i : v.serverPKIs) + write(i); + + write(v.serverCustomPKIs.size()); + for (auto i : v.serverCustomPKIs) + writePODVector(i); +} + +template<> +void MemStreamReader::read(nsysnet::NSSLInternalState_t& v) +{ + readBool(v.destroyed); + read(v.sslVersion); + read(v.clientPKI); + + uint32 serverPKIsSize = read(); + v.serverPKIs.clear(); + for (uint32 i = 0; i < serverPKIsSize; i++) + v.serverPKIs.insert(read()); + + uint32 serverCustomPKIsSize = read(); + v.serverCustomPKIs.clear(); + v.serverCustomPKIs.resize(serverCustomPKIsSize); + for (uint32 i = 0; i < serverCustomPKIsSize; i++) + { + std::vector pki; + readPODVector(pki); + v.serverCustomPKIs.push_back(pki); + } +} + +void nsysnet_save(MemStreamWriter& s) +{ + s.writeSection("nsysnet"); + s.writeMPTR(_ntoa_tempString); + s.writeMPTR(_staticHostent); + s.writeMPTR(_staticHostentName); + s.writeMPTR(_staticHostentPtrList); + s.writeMPTR(_staticHostentEntries); + s.write(nsysnet::g_nsslInternalStates.size()); + for (auto i : nsysnet::g_nsslInternalStates) + s.write(i); + s.writeBool(sockLibReady); + s.write(sizeof(virtualSocket_t) * WU_SOCKET_LIMIT); + s.writeData(virtualSocketTable, sizeof(virtualSocket_t) * WU_SOCKET_LIMIT); +} + +void nsysnet_restore(MemStreamReader& s) +{ + s.readSection("nsysnet"); + s.readMPTR(_ntoa_tempString); + s.readMPTR(_staticHostent); + s.readMPTR(_staticHostentName); + s.readMPTR(_staticHostentPtrList); + s.readMPTR(_staticHostentEntries); + uint32 g_nsslInternalStatesSize = s.read(); + nsysnet::g_nsslInternalStates.clear(); + nsysnet::g_nsslInternalStates.resize(g_nsslInternalStatesSize); + for (uint32 i = 0; i < g_nsslInternalStatesSize; i++) + { + nsysnet::NSSLInternalState_t t; + s.read(t); + nsysnet::g_nsslInternalStates.push_back(t); + } + s.readBool(sockLibReady); + cemu_assert(s.read() == sizeof(virtualSocket_t) * WU_SOCKET_LIMIT); + s.readData(virtualSocketTable, sizeof(virtualSocket_t) * WU_SOCKET_LIMIT); +} + // register nsysnet functions void nsysnet_load() { @@ -2283,3 +2360,4 @@ void nsysnet_load() osLib_addFunction("nsysnet", "NSSLExportInternalServerCertificate", nsysnet::export_NSSLExportInternalServerCertificate); osLib_addFunction("nsysnet", "NSSLExportInternalClientCertificate", nsysnet::export_NSSLExportInternalClientCertificate); } + diff --git a/src/Cafe/OS/libs/nsysnet/nsysnet.h b/src/Cafe/OS/libs/nsysnet/nsysnet.h index fa2f2ca40a..ce93171473 100644 --- a/src/Cafe/OS/libs/nsysnet/nsysnet.h +++ b/src/Cafe/OS/libs/nsysnet/nsysnet.h @@ -12,6 +12,9 @@ typedef signed int WUSOCKET; +void nsysnet_save(MemStreamWriter& s); +void nsysnet_restore(MemStreamReader& s); + void nsysnet_load(); WUSOCKET nsysnet_createVirtualSocketFromExistingSocket(SOCKET existingSocket); void nsysnet_notifyCloseSharedSocket(SOCKET existingSocket); diff --git a/src/Cafe/OS/libs/padscore/padscore.cpp b/src/Cafe/OS/libs/padscore/padscore.cpp index 2f3597481c..6d27d56d59 100644 --- a/src/Cafe/OS/libs/padscore/padscore.cpp +++ b/src/Cafe/OS/libs/padscore/padscore.cpp @@ -54,7 +54,8 @@ namespace padscore WPADState_t g_wpad_state = kWPADStateMaster; - struct { + typedef struct _g_padscore_t + { SysAllocator alarm; bool kpad_initialized = false; @@ -72,7 +73,9 @@ namespace padscore } controller_data[InputManager::kMaxWPADControllers] = {}; int max_controllers = kWPADMaxControllers; // max bt controllers? - } g_padscore; + } g_padscore_t; + + g_padscore_t g_padscore; } @@ -808,3 +811,73 @@ namespace padscore } } + +template<> +void MemStreamWriter::write(const padscore::g_padscore_t& v) +{ + writeMPTR(v.alarm); + writeBool(v.kpad_initialized); + write(InputManager::kMaxWPADControllers); + for (auto i : v.controller_data) + { + writeMPTR(i.extension_callback); + writeMPTR(i.connectCallback); + writeMPTR(i.sampling_callback); + writeMPTR(i.dpd_callback); + writeBool(i.dpd_enabled); + writeBool(i.disconnectCalled); + writeBool(i.disconnectCalled); + write(i.btn_repeat.delay); + write(i.btn_repeat.pulse); + } + write(v.max_controllers); +} + +template <> +void MemStreamReader::read(padscore::g_padscore_t& v) +{ + readMPTR(v.alarm); + readBool(v.kpad_initialized); + cemu_assert(read() == InputManager::kMaxWPADControllers); + for (auto i : v.controller_data) + { + readMPTR(i.extension_callback); + readMPTR(i.connectCallback); + readMPTR(i.sampling_callback); + readMPTR(i.dpd_callback); + readBool(i.dpd_enabled); + readBool(i.disconnectCalled); + readBool(i.disconnectCalled); + read(i.btn_repeat.delay); + read(i.btn_repeat.pulse); + } + read(v.max_controllers); +} + +namespace padscore +{ + void save(MemStreamWriter& s) + { + s.writeSection("padscore"); + s.writeBool(debugUseDRC1); + s.writeBool(g_kpadIsInited); + s.write(g_padscore); + s.writePTR(g_kpad_ringbuffer); + s.write(g_kpad_ringbuffer_length); + s.writeBool(g_wpad_callback_by_kpad); + s.write((uint32)g_wpad_state); + } + + void restore(MemStreamReader& s) + { + s.readSection("padscore"); + s.readBool(debugUseDRC1); + s.readBool(g_kpadIsInited); + s.read(g_padscore); + s.readPTR(g_kpad_ringbuffer); + s.read(g_kpad_ringbuffer_length); + s.readBool(g_wpad_callback_by_kpad); + g_wpad_state = (WPADState_t)s.read(); + } +} + diff --git a/src/Cafe/OS/libs/padscore/padscore.h b/src/Cafe/OS/libs/padscore/padscore.h index efb1fbca16..3232006186 100644 --- a/src/Cafe/OS/libs/padscore/padscore.h +++ b/src/Cafe/OS/libs/padscore/padscore.h @@ -4,6 +4,9 @@ namespace padscore { + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); + void start(); void load(); } diff --git a/src/Cafe/OS/libs/proc_ui/proc_ui.cpp b/src/Cafe/OS/libs/proc_ui/proc_ui.cpp index ff38abbb6c..156f50460a 100644 --- a/src/Cafe/OS/libs/proc_ui/proc_ui.cpp +++ b/src/Cafe/OS/libs/proc_ui/proc_ui.cpp @@ -875,6 +875,16 @@ namespace proc_ui s_driverInBackground = false; } + void save(MemStreamWriter& s) + { + s.writeSection("proc_ui"); + } + + void restore(MemStreamReader& s) + { + s.readSection("proc_ui"); + } + void load() { reset(); diff --git a/src/Cafe/OS/libs/proc_ui/proc_ui.h b/src/Cafe/OS/libs/proc_ui/proc_ui.h index 8de7bb4df5..2bbdabb30d 100644 --- a/src/Cafe/OS/libs/proc_ui/proc_ui.h +++ b/src/Cafe/OS/libs/proc_ui/proc_ui.h @@ -40,5 +40,7 @@ namespace proc_ui ProcUIStatus ProcUIProcessMessages(bool isBlockingInBackground); ProcUIStatus ProcUISubProcessMessages(bool isBlockingInBackground); + void save(MemStreamWriter& s); + void restore(MemStreamReader& s); void load(); } \ No newline at end of file diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h index 5b2e5fa405..c5edfff575 100644 --- a/src/Cemu/Logging/CemuLogging.h +++ b/src/Cemu/Logging/CemuLogging.h @@ -43,6 +43,8 @@ enum class LogType : sint32 ProcUi = 39, nlibcurl = 41, + SaveStates = 50, + PRUDP = 40, NFC = 41, diff --git a/src/Common/SysAllocator.h b/src/Common/SysAllocator.h index 7a11601e3b..e47065e3f0 100644 --- a/src/Common/SysAllocator.h +++ b/src/Common/SysAllocator.h @@ -54,6 +54,12 @@ class SysAllocator : public SysAllocatorBase m_tempData.insert(m_tempData.begin(), str, str + N); } + SysAllocator& operator=(T* value) + { + m_sysMem = value; + return *this; + } + constexpr uint32 GetCount() const { return count; @@ -175,6 +181,12 @@ class SysAllocator : public SysAllocatorBase return *this; } + SysAllocator& operator=(T* value) + { + m_sysMem = value; + return *this; + } + operator T() { return *GetPtr(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 48bdd7d726..d648037c75 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -78,6 +78,8 @@ enum MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, + MAINFRAME_MENU_ID_FILE_SAVESTATE, + MAINFRAME_MENU_ID_FILE_LOADSTATE, MAINFRAME_MENU_ID_FILE_EXIT, MAINFRAME_MENU_ID_FILE_END_EMULATION, MAINFRAME_MENU_ID_FILE_RECENT_0, @@ -127,6 +129,13 @@ enum MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE = 21000, MAINFRAME_MENU_ID_NFC_RECENT_0, MAINFRAME_MENU_ID_NFC_RECENT_LAST = MAINFRAME_MENU_ID_NFC_RECENT_0 + 15, + + // savestates + MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE, + MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE, + MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE, + MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE, + // debug MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN = 21100, MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW, @@ -202,6 +211,11 @@ EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_0125X, MainWindow::OnDebugSetting) // nfc menu EVT_MENU(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, MainWindow::OnNFCMenu) EVT_MENU_RANGE(MAINFRAME_MENU_ID_NFC_RECENT_0 + 0, MAINFRAME_MENU_ID_NFC_RECENT_LAST, MainWindow::OnNFCMenu) +// savestates menu +EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE, MainWindow::OnSavestatesMenu) +EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE, MainWindow::OnSavestatesMenu) +EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE, MainWindow::OnSavestatesMenu) +EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE, MainWindow::OnSavestatesMenu) // debug -> logging menu EVT_MENU_RANGE(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 0, MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 98, MainWindow::OnDebugLoggingToggleFlagGeneric) EVT_MENU(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, MainWindow::OnPPCInfoToggle) @@ -777,6 +791,27 @@ void MainWindow::OnNFCMenu(wxCommandEvent& event) } } +void MainWindow::OnSavestatesMenu(wxCommandEvent& event) +{ + const auto menuId = event.GetId(); + if (menuId == MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE) + { + CafeSystem::PauseTitle(); + } + if (menuId == MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE) + { + CafeSystem::ResumeTitle(); + } + else if (menuId == MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE) + { + CafeSystem::SaveState("state.bin"); + } + else if (menuId == MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE) + { + CafeSystem::LoadState("state.bin"); + } +} + void MainWindow::OnFileExit(wxCommandEvent& event) { // todo: Safely clean up everything @@ -2196,6 +2231,16 @@ void MainWindow::RecreateMenu() nfcMenu->Append(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, _("&Scan NFC tag from file"))->Enable(false); m_menuBar->Append(nfcMenu, _("&NFC")); m_nfcMenuSeparator0 = nullptr; + + // savestates menu + wxMenu* savestatesMenu = new wxMenu; + savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE, _("&Pause"), wxEmptyString); + savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE, _("&Resume"), wxEmptyString); + savestatesMenu->AppendSeparator(); + savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE, _("&Save state"), wxEmptyString); + savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE, _("&Load state"), wxEmptyString); + m_menuBar->Append(savestatesMenu, _("&Savestates")); + // debug->logging submenu wxMenu* debugLoggingMenu = new wxMenu(); @@ -2230,6 +2275,7 @@ void MainWindow::RecreateMenu() debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Patches), _("&Graphic pack patches"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Patches)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::TextureCache), _("&Texture cache warnings"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::TextureCache)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::TextureReadback), _("&Texture readback"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::TextureReadback)); + debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SaveStates), _("&Save states"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SaveStates)); debugLoggingMenu->AppendSeparator(); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), _("&OpenGL debug output"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::OpenGLLogging)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), _("&Vulkan validation layer (slow)"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::VulkanValidation)); diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index beb86f98b0..da42d63285 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -99,6 +99,7 @@ class MainWindow : public wxFrame, public CafeSystem::SystemImplementation void OnInstallUpdate(wxCommandEvent& event); void OnFileExit(wxCommandEvent& event); void OnNFCMenu(wxCommandEvent& event); + void OnSavestatesMenu(wxCommandEvent& event); void OnOptionsInput(wxCommandEvent& event); void OnAccountSelect(wxCommandEvent& event); void OnConsoleLanguage(wxCommandEvent& event); @@ -232,6 +233,12 @@ class MainWindow : public wxFrame, public CafeSystem::SystemImplementation wxMenu* m_nfcMenu{}; wxMenuItem* m_nfcMenuSeparator0{}; + // savestates + //wxMenuItem* m_pause; + //wxMenuItem* m_resume; + //wxMenuItem* m_saveState; + //wxMenuItem* m_loadState; + // debug wxMenu* m_debugMenu{}; wxMenu* m_loggingSubmenu{}; diff --git a/src/util/helpers/Serializer.cpp b/src/util/helpers/Serializer.cpp index e9e60b0afc..fd63b93c1f 100644 --- a/src/util/helpers/Serializer.cpp +++ b/src/util/helpers/Serializer.cpp @@ -1,54 +1,111 @@ #include "Serializer.h" -template<> -uint8 MemStreamReader::readBE() -{ - if (!reserveReadLength(sizeof(uint8))) - return 0; - uint8 v = m_data[m_cursorPos]; - m_cursorPos += sizeof(uint8); - return v; -} +// read return -template<> -uint16 MemStreamReader::readBE() +template +T MemStreamReader::read() { - if (!reserveReadLength(sizeof(uint16))) + if (!reserveReadLength(sizeof(T))) return 0; const uint8* p = m_data + m_cursorPos; - uint16 v; + T v; std::memcpy(&v, p, sizeof(v)); - v = _BE(v); - m_cursorPos += sizeof(uint16); + m_cursorPos += sizeof(T); return v; } +template uint8 MemStreamReader::read(); +template uint16 MemStreamReader::read(); +template uint32 MemStreamReader::read(); +template uint32be MemStreamReader::read(); +template uint64 MemStreamReader::read(); +template int MemStreamReader::read(); + template<> -uint32 MemStreamReader::readBE() +std::string MemStreamReader::read() { - if (!reserveReadLength(sizeof(uint32))) - return 0; - const uint8* p = m_data + m_cursorPos; - uint32 v; - std::memcpy(&v, p, sizeof(v)); - v = _BE(v); - m_cursorPos += sizeof(uint32); - return v; + std::string s; + uint32 stringSize = read(); + if (hasError()) + return s; + if (stringSize >= (32 * 1024 * 1024)) + { + // out of bounds read or suspiciously large string + m_hasError = true; + return std::string(); + } + s.resize(stringSize); + readData(s.data(), stringSize); + return s; } +// read void + +template +void MemStreamReader::read(T& v) +{ + if (reserveReadLength(sizeof(T))) + { + const uint8* p = m_data + m_cursorPos; + std::memcpy(&v, p, sizeof(v)); + m_cursorPos += sizeof(T); + } +} + +template void MemStreamReader::read(uint8& v); +template void MemStreamReader::read(uint16& v); +template void MemStreamReader::read(uint32& v); +template void MemStreamReader::read(uint32be& v); +template void MemStreamReader::read(uint64& v); +template void MemStreamReader::read(int& v); + template<> -uint64 MemStreamReader::readBE() +void MemStreamReader::read(std::string& v) +{ + uint32 stringSize = read(); + if (!hasError()) + { + if (stringSize >= (32 * 1024 * 1024)) + { + // out of bounds read or suspiciously large string + m_hasError = true; + } + else + { + v.resize(stringSize); + readData(v.data(), stringSize); + } + } +} + +// readSection + +void MemStreamReader::readSection(const char* sec) { - if (!reserveReadLength(sizeof(uint64))) + std::string sec_str = std::string(sec); + cemu_assert_debug(read() == sec_str); +} + +// readBE return + +template +T MemStreamReader::readBE() +{ + if (!reserveReadLength(sizeof(T))) return 0; const uint8* p = m_data + m_cursorPos; - uint64 v; + T v; std::memcpy(&v, p, sizeof(v)); v = _BE(v); - m_cursorPos += sizeof(uint64); + m_cursorPos += sizeof(T); return v; } +template uint8 MemStreamReader::readBE(); +template uint16 MemStreamReader::readBE(); +template uint32 MemStreamReader::readBE(); +template uint64 MemStreamReader::readBE(); + template<> std::string MemStreamReader::readBE() { @@ -67,73 +124,72 @@ std::string MemStreamReader::readBE() return s; } -template<> -uint8 MemStreamReader::readLE() -{ - return readBE(); -} +// readLE return -template<> -uint32 MemStreamReader::readLE() +template +T MemStreamReader::readLE() { - if (!reserveReadLength(sizeof(uint32))) + if (!reserveReadLength(sizeof(T))) return 0; const uint8* p = m_data + m_cursorPos; - uint32 v; + T v; std::memcpy(&v, p, sizeof(v)); v = _LE(v); - m_cursorPos += sizeof(uint32); + m_cursorPos += sizeof(T); return v; } -template<> -uint64 MemStreamReader::readLE() -{ - if (!reserveReadLength(sizeof(uint64))) - return 0; - const uint8* p = m_data + m_cursorPos; - uint64 v; - std::memcpy(&v, p, sizeof(v)); - v = _LE(v); - m_cursorPos += sizeof(uint64); - return v; -} +template uint8 MemStreamReader::readLE(); +template uint32 MemStreamReader::readLE(); +template uint64 MemStreamReader::readLE(); -template<> -void MemStreamWriter::writeBE(const uint64& v) +// write void + +template +void MemStreamWriter::write(const T& v) { - m_buffer.resize(m_buffer.size() + 8); - uint8* p = m_buffer.data() + m_buffer.size() - 8; - uint64 tmp = _BE(v); - std::memcpy(p, &tmp, sizeof(tmp)); + m_buffer.resize(m_buffer.size() + sizeof(T)); + uint8* p = m_buffer.data() + m_buffer.size() - sizeof(T); + std::memcpy(p, &v, sizeof(v)); } +template void MemStreamWriter::write(const int& v); +template void MemStreamWriter::write(const uint64& v); +template void MemStreamWriter::write(const uint32be& v); +template void MemStreamWriter::write(const uint32& v); +template void MemStreamWriter::write(const uint16& v); +template void MemStreamWriter::write(const uint8& v); + template<> -void MemStreamWriter::writeBE(const uint32& v) +void MemStreamWriter::write(const std::string& v) { - m_buffer.resize(m_buffer.size() + 4); - uint8* p = m_buffer.data() + m_buffer.size() - 4; - uint32 tmp = _BE(v); - std::memcpy(p, &tmp, sizeof(tmp)); + write((uint32)v.size()); + writeData(v.data(), v.size()); } +// writeSection -template<> -void MemStreamWriter::writeBE(const uint16& v) +void MemStreamWriter::writeSection(const char* sec) { - m_buffer.resize(m_buffer.size() + 2); - uint8* p = m_buffer.data() + m_buffer.size() - 2; - uint16 tmp = _BE(v); - std::memcpy(p, &tmp, sizeof(tmp)); + std::string sec_str = std::string(sec); + write(sec_str); } +// writeBE void -template<> -void MemStreamWriter::writeBE(const uint8& v) +template +void MemStreamWriter::writeBE(const T& v) { - m_buffer.emplace_back(v); + m_buffer.resize(m_buffer.size() + sizeof(T)); + uint8* p = m_buffer.data() + m_buffer.size() - sizeof(T); + T tmp = _BE(v); + std::memcpy(p, &tmp, sizeof(tmp)); } +template void MemStreamWriter::writeBE(const uint64& v); +template void MemStreamWriter::writeBE(const uint32& v); +template void MemStreamWriter::writeBE(const uint16& v); +template void MemStreamWriter::writeBE(const uint8& v); template<> void MemStreamWriter::writeBE(const std::string& v) @@ -142,21 +198,17 @@ void MemStreamWriter::writeBE(const std::string& v) writeData(v.data(), v.size()); } -template<> -void MemStreamWriter::writeLE(const uint64& v) +// writeLE void + +template +void MemStreamWriter::writeLE(const T& v) { - m_buffer.resize(m_buffer.size() + 8); - uint8* p = m_buffer.data() + m_buffer.size() - 8; - uint64 tmp = _LE(v); + m_buffer.resize(m_buffer.size() + sizeof(T)); + uint8* p = m_buffer.data() + m_buffer.size() - sizeof(T); + T tmp = _LE(v); std::memcpy(p, &tmp, sizeof(tmp)); } +template void MemStreamWriter::writeLE(const uint64& v); +template void MemStreamWriter::writeLE(const uint32& v); -template<> -void MemStreamWriter::writeLE(const uint32& v) -{ - m_buffer.resize(m_buffer.size() + 4); - uint8* p = m_buffer.data() + m_buffer.size() - 4; - uint32 tmp = _LE(v); - std::memcpy(p, &tmp, sizeof(tmp)); -} \ No newline at end of file diff --git a/src/util/helpers/Serializer.h b/src/util/helpers/Serializer.h index a4941c299d..f5d474c49a 100644 --- a/src/util/helpers/Serializer.h +++ b/src/util/helpers/Serializer.h @@ -8,9 +8,23 @@ class MemStreamReader m_cursorPos = 0; } + template T read(); + template void read(T& v); template T readBE(); + template void readBE(T& v); template T readLE(); + void readAtomic(std::atomic& v) + { + v.store(readBool()); + } + + template + void readAtomic(std::atomic& v) + { + v.store(read()); + } + template std::vector readPODVector() { @@ -26,6 +40,48 @@ class MemStreamReader return v; } + template + void readPODVector(std::vector& v) + { + uint32 numElements = readBE(); + if (!hasError()) + { + v.reserve(numElements); + v.resize(numElements); + readData(v.data(), v.size() * sizeof(T)); + } + } + + template + void readPTR(T& v) + { + v = (T)(memory_base + read()); + } + + template class C, typename T> + void readMPTR(C& v) + { + v = (T*)(memory_base + read()); + } + + template class C, typename T, size_t c, size_t a> + void readMPTR(C& v) + { + v = (T*)(memory_base + read()); + } + + void readBool(bool& v) + { + v = read(); + } + + bool readBool() + { + return read(); + } + + void readSection(const char* sec); + // read string terminated by newline character (or end of stream) // will also trim off any carriage return std::string_view readLine() @@ -81,6 +137,19 @@ class MemStreamReader return true; } + bool readNullableData(void* ptr, size_t size) + { + if (readBE()) + { + ptr = NULL; + return false; + } + else + { + return readData(ptr, size); + } + } + std::span readDataNoCopy(size_t size) { if (m_cursorPos + size > m_size) @@ -151,16 +220,55 @@ class MemStreamWriter memcpy(p, ptr, size); } + void writeNullableData(void* ptr, size_t size) + { + writeBE((uint8)(ptr == NULL)); + if (ptr) + writeData(ptr, size); + } + + template void write(const T& v); template void writeBE(const T& v); template void writeLE(const T& v); + + void writeAtomic(const std::atomic& v) + { + writeBool(v.load()); + } + + template + void writeAtomic(const std::atomic& v) + { + write(v.load()); + } template void writePODVector(const std::vector& v) { + cemu_assert(std::is_trivial_v); writeBE(v.size()); writeData(v.data(), v.size() * sizeof(T)); } + template + void writePTR(const T& v) + { + write((uint32)((uint8*)v - (uint8*)memory_base)); + } + + template + void writeMPTR(const T& v) + { + write(v.GetMPTR()); + } + + void writeBool(const bool& v) + { + write((uint8)v); + } + + void writeSection(const char* sec); + // get result buffer without copy // resets internal state void getResultAndReset(std::vector& data)