This commit is contained in:
Spegs21 2025-07-01 10:30:15 +02:00 committed by GitHub
commit d5eda5501c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
99 changed files with 2029 additions and 115 deletions

View file

@ -68,6 +68,8 @@
// dependency to be removed
#include "gui/guiWrapper.h"
#include "Cafe/OS/libs/coreinit/coreinit_FS.h"
#include <time.h>
#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()

View file

@ -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();

View file

@ -338,6 +338,8 @@ public:
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<FSCVirtualFile::FSCDirIteratorState>(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>((uint32)Child::DIRECTORY_ITERATOR);
writer.write(m_path);
writer.write<uint32>(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<uint32>())
{
case Child::DIRECTORY_ITERATOR:
{
std::string path = reader.read<std::string>();
std::vector<FSCVirtualFile*> folders{};
size_t size = reader.read<uint32>();
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<std::string>();
FSC_ACCESS_FLAG flags = (FSC_ACCESS_FLAG)reader.read<uint32>();
sint32 status{};
file = FSCVirtualFile_Host::OpenFile(path, flags, status);
file->fscSetSeek(reader.read<uint64>());
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;
}

View file

@ -89,12 +89,20 @@ public:
struct FSCVirtualFile
{
enum class Child : uint32
{
DIRECTORY_ITERATOR, HOST, WUACTX, WUDCTX, NONE
};
struct FSCDirIteratorState
{
sint32 index;
std::vector<FSCDirEntry> dirEntries;
};
virtual void Save(MemStreamWriter& writer);
static FSCVirtualFile* Restore(MemStreamReader& reader);
FSCVirtualFile()
{

View file

@ -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 @@ public:
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;
}
}
void FSCVirtualFile_Host::Save(MemStreamWriter& writer)
{
writer.write<uint32>((uint32)Child::HOST);
writer.write(m_path->string());
writer.write((uint32)m_accessFlags);
writer.write(m_seek);
FSCVirtualFile::Save(writer);
}

View file

@ -18,6 +18,8 @@ public:
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 @@ private:
// directory
std::unique_ptr<std::filesystem::path> m_path{};
std::unique_ptr<std::filesystem::directory_iterator> m_dirIterator{};
// serialization
FSC_ACCESS_FLAG m_accessFlags;
};

View file

@ -107,6 +107,11 @@ public:
return true;
}
void Save(MemStreamWriter& writer) override
{
throw std::exception("Not implemented");
}
private:
ZArchiveReader* m_archive{nullptr};
sint32 m_fscType;

View file

@ -108,6 +108,11 @@ public:
return true;
}
void Save(MemStreamWriter& writer) override
{
throw std::exception("Not implemented");
}
private:
FSTVolume* m_volume{nullptr};
sint32 m_fscType;

View file

@ -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<uint8>();
v.flags = (MMURange::MFLAG)read<uint8>();
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

View file

@ -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<size_t count>
void memory_readBytes(VAddr address, std::array<uint8, count>& buffer)
{

View file

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

View file

@ -4,6 +4,9 @@ namespace iosu
{
namespace odm
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void Initialize();
void Shutdown();
}

View file

@ -409,6 +409,15 @@ namespace iosu
}
}
void save(MemStreamWriter& s)
{
}
void restore(MemStreamReader& s)
{
}
class : public ::IOSUModule
{
void PDMLoadAll()

View file

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

View file

@ -36,7 +36,9 @@ namespace iosu
}
};
std::array<FSAClient, 624> sFSAClientArray;
static constexpr int const sFSAClientArraySize = 624;
std::array<FSAClient, sFSAClientArraySize> 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

View file

@ -213,5 +213,8 @@ namespace iosu
void Initialize();
void Shutdown();
void save(MemStreamWriter& writer);
void restore(MemStreamReader& reader);
} // namespace fsa
} // namespace iosu

View file

@ -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<IOSUModule*>(&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<uint32>(sMsgQueuePool.size());
for (const auto& i : sMsgQueuePool)
s.write(i);
s.write<uint32>(sDeviceResources.size());
for (const auto& i : sDeviceResources)
s.write(i);
s.writeMPTR(sIPCDispatchableCommandPool);
size_t sIPCFreeDispatchableCommandsSize = sIPCFreeDispatchableCommands.size();
s.write<uint32>(sIPCFreeDispatchableCommandsSize);
while (sIPCFreeDispatchableCommandsSize)
{
IOSDispatchableCommand* front = sIPCFreeDispatchableCommands.front();
sIPCFreeDispatchableCommands.pop();
s.writePTR(front);
sIPCFreeDispatchableCommands.push(front);
sIPCFreeDispatchableCommandsSize--;
}
s.write<uint32>(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<uint32>() == sMsgQueuePool.size());
for (auto& i : sMsgQueuePool)
s.read(i);
cemu_assert(s.read<uint32>() == sDeviceResources.size());
for (auto& i : sDeviceResources)
s.read(i);
s.readMPTR(sIPCDispatchableCommandPool);
size_t sIPCFreeDispatchableCommandsSize = s.read<uint32>();
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<uint32>() == MAX_NUM_ACTIVE_DEV_HANDLES);
for (uint32 i = 0; i < MAX_NUM_ACTIVE_DEV_HANDLES; i++)
s.read(sActiveDeviceHandles[i]);
}
}
}

View file

@ -24,5 +24,8 @@ namespace iosu
void IPCSubmitFromCOS(uint32 ppcCoreIndex, IPCCommandBody* cmd);
IOSUModule* GetModule();
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
}
}

View file

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

View file

@ -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);

View file

@ -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<std::recursive_mutex> _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);
}
}
}

View file

@ -6,5 +6,8 @@ namespace camera
sint32 CAMOpen(sint32 camHandle);
sint32 CAMClose(sint32 camHandle);
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void load();
};

View file

@ -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();

View file

@ -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);

View file

@ -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<uint64_t>();
size_t alms = s.read<uint64>();
for (size_t alm = 0; alm < alms; alm++)
{
OSAlarm_t* alarm = (OSAlarm_t*)memory_getPointerFromVirtualOffset(s.read<MPTR>());
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<uint64>() + timeOffset;
__OSLockScheduler();
g_activeAlarms[alarm] = OSHostAlarmCreate(nextFire, period, __OSHostAlarmTriggered, nullptr);
__OSUnlockScheduler();
}
}
void _OSAlarmThread(PPCInterpreter_t* hCPU)
{
while( true )

View file

@ -47,6 +47,9 @@ namespace coreinit
void OSAlarm_Shutdown();
void Alarm_Save(MemStreamWriter& s);
void Alarm_Restore(MemStreamReader& s);
void alarm_update();
void InitializeAlarm();

View file

@ -31,6 +31,19 @@ struct CoreinitAsyncCallback
s_asyncCallbackSpinlock.unlock();
}
static std::vector<struct CoreinitAsyncCallback*>& getPool()
{
return s_asyncCallbackPool;
}
static std::vector<struct CoreinitAsyncCallback*>& 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);

View file

@ -25,9 +25,10 @@ namespace coreinit
}
}
static constexpr uint32 const codegenSize = 0x01000000; // todo: Read from cos.xml
void OSGetCodegenVirtAddrRange(betype<uint32>* rangeStart, betype<uint32>* 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<uint32>() == codegenSize);
s.readNullableData(coreinitCodeGen.cacheStateCopy, codegenSize);
}
void InitializeCodeGen()
{
cafeExportRegister("coreinit", OSGetCodegenVirtAddrRange, LogType::Placeholder);

View file

@ -6,5 +6,8 @@ namespace coreinit
void codeGenHandleICBI(uint32 ea);
bool codeGenShouldAvoid();
void CodeGen_Save(MemStreamWriter& s);
void CodeGen_Restore(MemStreamReader& s);
void InitializeCodeGen();
}

View file

@ -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);

View file

@ -20,5 +20,8 @@ namespace coreinit
void OSDynLoad_Release(uint32 moduleHandle);
uint32 OSDynLoad_FindExport(uint32 moduleHandle, uint32 isData, const char* exportName, betype<MPTR>* addrOut);
void DynLoad_Save(MemStreamWriter& s);
void DynLoad_Restore(MemStreamReader& s);
void InitializeDynLoad();
}

View file

@ -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);

View file

@ -13,5 +13,8 @@ namespace coreinit
void InitForegroundBucket();
void FG_Save(MemStreamWriter& s);
void FG_Restore(MemStreamReader& s);
void InitializeFG();
}

View file

@ -2645,6 +2645,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);

View file

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

View file

@ -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<uint8*>(_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<bool*>(_flockMutexMaskTmp), sizeof(bool) * GHS_FOPEN_MAX);
}
void InitializeGHS()
{
cafeExportRegister("coreinit", __ghs_flock_create, LogType::Placeholder);

View file

@ -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();
};

View file

@ -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);
}
};

View file

@ -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<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam);
void IPC_Save(MemStreamWriter& s);
void IPC_Restore(MemStreamReader& s);
void InitializeIPC();
};

View file

@ -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);
}

View file

@ -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++)

View file

@ -2,5 +2,8 @@
namespace coreinit
{
void LockedCache_Save(MemStreamWriter& s);
void LockedCache_Restore(MemStreamReader& s);
void InitializeLC();
}

View file

@ -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();

View file

@ -179,5 +179,8 @@ namespace coreinit
void InitializeMEMUnitHeap();
void MEM_Save(MemStreamWriter& s);
void MEM_Restore(MemStreamReader& s);
void InitializeMEM();
}

View file

@ -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<uint32>(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<uint32>();
s_allocatedVirtMemory.clear();
s_allocatedVirtMemory.reserve(s_allocatedVirtMemorySize);
for (sint32 i = 0; i < s_allocatedVirtMemorySize; i++)
{
s_allocatedVirtMemory.emplace_back(s.read<MPTR>(), s.read<uint32>(), s.read<uint32>());
}
}
void InitializeMemoryMapping()
{
s_allocatedVirtMemory.clear();

View file

@ -1,5 +1,8 @@
namespace coreinit
{
void MemoryMapping_Save(MemStreamWriter& s);
void MemoryMapping_Restore(MemStreamReader& s);
void InitializeMemoryMapping();
}

View file

@ -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());

View file

@ -47,5 +47,8 @@ namespace coreinit
OSMessageQueue* OSGetSystemMessageQueue();
void MessageQueue_Save(MemStreamWriter& s);
void MessageQueue_Restore(MemStreamReader& s);
void InitializeMessageQueue();
};

View file

@ -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);

View file

@ -1,4 +1,7 @@
namespace coreinit
{
void OverlayArena_Save(MemStreamWriter& s);
void OverlayArena_Restore(MemStreamReader& s);
void InitializeOverlayArena();
};

View file

@ -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()

View file

@ -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);

View file

@ -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();
}

View file

@ -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);

View file

@ -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();
};

View file

@ -14,6 +14,7 @@
#include "util/Fiber/Fiber.h"
#include "util/helpers/helpers.h"
#include "Common/FileStream.h"
SlimRWLock srwlock_activeThreadList;
@ -1564,6 +1565,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<sint32>();
for (sint32 i = 0; i < prevActiveThreadCount; i++)
{
MPTR threadMPTR = s.read<MPTR>();
if (recreate)
{
auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(threadMPTR);
__OSLockScheduler();
__OSActivateThread(ptr);
__OSUnlockScheduler();
//ptr->state = betype((OSThread_t::THREAD_STATE)s.read<uint8>());
}
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);

View file

@ -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();

View file

@ -118,6 +118,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()
{

View file

@ -1 +1,4 @@
void dmae_save(MemStreamWriter& s);
void dmae_restore(MemStreamReader& s);
void dmae_load();

View file

@ -1503,6 +1503,29 @@ CURLcode curl_global_init_mem(uint32 flags, MEMPTR<curl_malloc_callback> 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);

View file

@ -2,5 +2,8 @@
namespace nlibcurl
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void load();
}

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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<uint32>();
}
// register account functions
void nnAct_load()
{

View file

@ -33,4 +33,7 @@ namespace act
}
}
void nnAct_save(MemStreamWriter& s);
void nnAct_restore(MemStreamReader& s);
void nnAct_load();

View file

@ -149,6 +149,30 @@ namespace nn
return AOC_RESULT::ERROR_OK;
}
void save(MemStreamWriter& s)
{
s.writeSection("nn_aoc");
s.write<uint32>(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<uint32>();
sAocCache.clear();
sAocCache.reserve(sAocCacheSize);
for (sint32 i = 0; i < sAocCacheSize; i++)
{
sAocCache.emplace_back(s.read<uint64>());
}
s.readBool(sAocCacheGenerated);
}
void Initialize()
{
cafeExportRegister("nn_aoc", AOC_CalculateWorkBufferSize, LogType::NN_AOC);

View file

@ -2,6 +2,9 @@ namespace nn
{
namespace aoc
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void Initialize();
}
}

View file

@ -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);

View file

@ -1 +1,4 @@
void nnBoss_save(MemStreamWriter& s);
void nnBoss_restore(MemStreamReader& s);
void nnBoss_load();

View file

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

View file

@ -3,6 +3,9 @@ namespace nn
{
namespace fp
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void load();
}
}

View file

@ -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<NUM_DAEMONS; i++)

View file

@ -2,6 +2,9 @@ namespace nn
{
namespace ndm
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void load();
}
}

View file

@ -1040,6 +1040,50 @@ namespace nn::nfp
osLib_addFunction("nn_nfp", "GetAmiiboSettingsArgs__Q2_2nn3nfpFPQ3_2nn3nfp18AmiiboSettingsArgs", nnNfpExport_GetAmiiboSettingsArgs);
}
void save(MemStreamWriter& s)
{
s.writeSection("nn_nfp");
s.writeBool(nfp_data.nfpIsInitialized);
s.write(nfp_data.activateEvent);
s.write(nfp_data.deactivateEvent);
s.writeBool(nfp_data.isDetecting);
s.writeBool(nfp_data.isMounted);
s.writeBool(nfp_data.isReadOnly);
s.writeBool(nfp_data.hasOpenApplicationArea);
s.writeBool(nfp_data.hasActiveAmiibo);
s.writeBool(nfp_data.hasInvalidHMAC);
s.write(nfp_data.amiiboTouchTime);
s.write<uint32>(sizeof(AmiiboRawNFCData));
s.writeData(&nfp_data.amiiboNFCData, sizeof(AmiiboRawNFCData));
s.write<uint32>(sizeof(AmiiboInternal));
s.writeData(&nfp_data.amiiboInternal, sizeof(AmiiboInternal));
s.write<uint32>(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<uint32>() == sizeof(AmiiboRawNFCData));
s.readData(&nfp_data.amiiboNFCData, sizeof(AmiiboRawNFCData));
cemu_assert(s.read<uint32>() == sizeof(AmiiboInternal));
s.readData(&nfp_data.amiiboInternal, sizeof(AmiiboInternal));
cemu_assert(s.read<uint32>() == sizeof(AmiiboProcessedData));
s.readData(&nfp_data.amiiboProcessedData, sizeof(AmiiboProcessedData));
}
void load()
{
nnNfp_load(); // legacy interface, update these to use cafeExportRegister / cafeExportRegisterFunc

View file

@ -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();
}

View file

@ -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<uint32>(sizeof(ParamPackStorage));
s.writeData(&g_ParamPack, sizeof(ParamPackStorage));
s.write<uint32>(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<uint32>() == sizeof(ParamPackStorage));
s.readData(&g_ParamPack, sizeof(ParamPackStorage));
cemu_assert(s.read<uint32>() == 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;

View file

@ -18,6 +18,9 @@ namespace nn
sint32 GetOlvAccessKey(uint32_t* pOutKey);
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void load();
void unload();
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -4,6 +4,9 @@ namespace nn
{
namespace save
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void load();
void ResetToDefaultState();

View file

@ -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);

View file

@ -2,5 +2,8 @@
namespace nn::temp
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void Initialize();
};

View file

@ -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
*/

View file

@ -1 +1,4 @@
void nnUds_save(MemStreamWriter& s);
void nnUds_restore(MemStreamReader& s);
void nnUds_load();

View file

@ -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<size_t>(); i++)
_devicePoolMask.set(i);
}
void load()
{
osLib_addFunction("nsyshid", "HIDAddClient", export_HIDAddClient);

View file

@ -8,5 +8,8 @@ namespace nsyshid
void DetachBackend(const std::shared_ptr<Backend>& backend);
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void load();
} // namespace nsyshid

View file

@ -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<uint32>(v.serverPKIs.size());
for (auto i : v.serverPKIs)
write<uint32>(i);
write<uint32>(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<uint32>();
v.serverPKIs.clear();
for (uint32 i = 0; i < serverPKIsSize; i++)
v.serverPKIs.insert(read<uint32>());
uint32 serverCustomPKIsSize = read<uint32>();
v.serverCustomPKIs.clear();
v.serverCustomPKIs.resize(serverCustomPKIsSize);
for (uint32 i = 0; i < serverCustomPKIsSize; i++)
{
std::vector<uint8> 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<uint32>(nsysnet::g_nsslInternalStates.size());
for (auto i : nsysnet::g_nsslInternalStates)
s.write(i);
s.writeBool(sockLibReady);
s.write<uint32>(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<uint32>();
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<uint32>() == 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);
}

View file

@ -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);

View file

@ -54,7 +54,8 @@ namespace padscore
WPADState_t g_wpad_state = kWPADStateMaster;
struct {
typedef struct _g_padscore_t
{
SysAllocator<coreinit::OSAlarm_t> 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<uint32>(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<uint32>() == 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<uint32>();
}
}

View file

@ -4,6 +4,9 @@
namespace padscore
{
void save(MemStreamWriter& s);
void restore(MemStreamReader& s);
void start();
void load();
}

View file

@ -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();

View file

@ -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();
}

View file

@ -42,6 +42,8 @@ enum class LogType : sint32
ProcUi = 39,
nlibcurl = 41,
SaveStates = 50,
PRUDP = 40,
NFC = 41,

View file

@ -54,6 +54,12 @@ public:
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 @@ public:
return *this;
}
SysAllocator& operator=(T* value)
{
m_sysMem = value;
return *this;
}
operator T()
{
return *GetPtr();

View file

@ -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,
@ -128,6 +130,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,
@ -206,6 +215,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)
@ -787,6 +801,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
@ -2226,6 +2261,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();
@ -2260,6 +2305,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));

View file

@ -99,6 +99,7 @@ public:
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);
@ -231,6 +232,12 @@ private:
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{};

View file

@ -1,53 +1,110 @@
#include "Serializer.h"
template<>
uint8 MemStreamReader::readBE()
// read return
template<typename T>
T MemStreamReader::read()
{
if (!reserveReadLength(sizeof(uint8)))
if (!reserveReadLength(sizeof(T)))
return 0;
uint8 v = m_data[m_cursorPos];
m_cursorPos += sizeof(uint8);
const uint8* p = m_data + m_cursorPos;
T v;
std::memcpy(&v, p, sizeof(v));
m_cursorPos += sizeof(T);
return v;
}
template uint8 MemStreamReader::read<uint8>();
template uint16 MemStreamReader::read<uint16>();
template uint32 MemStreamReader::read<uint32>();
template uint32be MemStreamReader::read<uint32be>();
template uint64 MemStreamReader::read<uint64>();
template int MemStreamReader::read<int>();
template<>
uint16 MemStreamReader::readBE()
std::string MemStreamReader::read()
{
if (!reserveReadLength(sizeof(uint16)))
std::string s;
uint32 stringSize = read<uint32>();
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<typename T>
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<>
void MemStreamReader::read(std::string& v)
{
uint32 stringSize = read<uint32>();
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)
{
std::string sec_str = std::string(sec);
cemu_assert_debug(read<std::string>() == sec_str);
}
// readBE return
template<typename T>
T MemStreamReader::readBE()
{
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<>
uint32 MemStreamReader::readBE()
{
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;
}
template<>
uint64 MemStreamReader::readBE()
{
if (!reserveReadLength(sizeof(uint64)))
return 0;
const uint8* p = m_data + m_cursorPos;
uint64 v;
std::memcpy(&v, p, sizeof(v));
v = _BE(v);
m_cursorPos += sizeof(uint64);
return v;
}
template uint8 MemStreamReader::readBE<uint8>();
template uint16 MemStreamReader::readBE<uint16>();
template uint32 MemStreamReader::readBE<uint32>();
template uint64 MemStreamReader::readBE<uint64>();
template<>
std::string MemStreamReader::readBE()
@ -67,73 +124,72 @@ std::string MemStreamReader::readBE()
return s;
}
template<>
uint8 MemStreamReader::readLE()
{
return readBE<uint8>();
}
// readLE return
template<>
uint32 MemStreamReader::readLE()
template<typename T>
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()
template uint8 MemStreamReader::readLE<uint8>();
template uint32 MemStreamReader::readLE<uint32>();
template uint64 MemStreamReader::readLE<uint64>();
// write void
template<typename T>
void MemStreamWriter::write(const T& v)
{
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;
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<uint64>(const uint64& v)
void MemStreamWriter::write<std::string>(const std::string& v)
{
m_buffer.resize(m_buffer.size() + 8);
uint8* p = m_buffer.data() + m_buffer.size() - 8;
uint64 tmp = _BE(v);
write<uint32>((uint32)v.size());
writeData(v.data(), v.size());
}
// writeSection
void MemStreamWriter::writeSection(const char* sec)
{
std::string sec_str = std::string(sec);
write(sec_str);
}
// writeBE void
template<typename T>
void MemStreamWriter::writeBE(const T& 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<uint32>(const uint32& 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));
}
template<>
void MemStreamWriter::writeBE<uint16>(const uint16& v)
{
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));
}
template<>
void MemStreamWriter::writeBE<uint8>(const uint8& v)
{
m_buffer.emplace_back(v);
}
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<std::string>(const std::string& v)
@ -142,21 +198,17 @@ void MemStreamWriter::writeBE<std::string>(const std::string& v)
writeData(v.data(), v.size());
}
template<>
void MemStreamWriter::writeLE<uint64>(const uint64& v)
// writeLE void
template<typename T>
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<uint32>(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));
}

View file

@ -8,9 +8,23 @@ public:
m_cursorPos = 0;
}
template<typename T> T read();
template<typename T> void read(T& v);
template<typename T> T readBE();
template<typename T> void readBE(T& v);
template<typename T> T readLE();
void readAtomic(std::atomic<bool>& v)
{
v.store(readBool());
}
template<typename T>
void readAtomic(std::atomic<T>& v)
{
v.store(read<T>());
}
template<typename T>
std::vector<T> readPODVector()
{
@ -26,6 +40,48 @@ public:
return v;
}
template<typename T>
void readPODVector(std::vector<T>& v)
{
uint32 numElements = readBE<uint32>();
if (!hasError())
{
v.reserve(numElements);
v.resize(numElements);
readData(v.data(), v.size() * sizeof(T));
}
}
template<typename T>
void readPTR(T& v)
{
v = (T)(memory_base + read<uint32>());
}
template<template<typename> class C, typename T>
void readMPTR(C<T>& v)
{
v = (T*)(memory_base + read<MPTR>());
}
template<template<typename, size_t, size_t> class C, typename T, size_t c, size_t a>
void readMPTR(C<T,c,a>& v)
{
v = (T*)(memory_base + read<MPTR>());
}
void readBool(bool& v)
{
v = read<uint8>();
}
bool readBool()
{
return read<uint8>();
}
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 @@ public:
return true;
}
bool readNullableData(void* ptr, size_t size)
{
if (readBE<uint8>())
{
ptr = NULL;
return false;
}
else
{
return readData(ptr, size);
}
}
std::span<uint8> readDataNoCopy(size_t size)
{
if (m_cursorPos + size > m_size)
@ -151,16 +220,55 @@ public:
memcpy(p, ptr, size);
}
void writeNullableData(void* ptr, size_t size)
{
writeBE((uint8)(ptr == NULL));
if (ptr)
writeData(ptr, size);
}
template<typename T> void write(const T& v);
template<typename T> void writeBE(const T& v);
template<typename T> void writeLE(const T& v);
void writeAtomic(const std::atomic<bool>& v)
{
writeBool(v.load());
}
template<typename T>
void writeAtomic(const std::atomic<T>& v)
{
write(v.load());
}
template<typename T>
void writePODVector(const std::vector<T>& v)
{
cemu_assert(std::is_trivial_v<T>);
writeBE<uint32>(v.size());
writeData(v.data(), v.size() * sizeof(T));
}
template<typename T>
void writePTR(const T& v)
{
write((uint32)((uint8*)v - (uint8*)memory_base));
}
template<typename T>
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<uint8>& data)