Skip to content
Draft
83 changes: 83 additions & 0 deletions src/Cafe/CafeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
6 changes: 6 additions & 0 deletions src/Cafe/CafeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
75 changes: 75 additions & 0 deletions src/Cafe/Filesystem/fsc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ class FSCVirtualFileDirectoryIterator : public FSCVirtualFile
dirIterator->dirEntries.emplace_back(dirEntry);
}

void Save(MemStreamWriter& writer) override;

private:
void PopulateIterationList()
{
Expand Down Expand Up @@ -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;
}
8 changes: 8 additions & 0 deletions src/Cafe/Filesystem/fsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,20 @@ class fscDeviceC

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

Expand Down
14 changes: 13 additions & 1 deletion src/Cafe/Filesystem/fscDeviceHostFS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
}

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);
}
4 changes: 4 additions & 0 deletions src/Cafe/Filesystem/fscDeviceHostFS.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {};

Expand All @@ -31,4 +33,6 @@ class FSCVirtualFile_Host : public FSCVirtualFile
// directory
std::unique_ptr<std::filesystem::path> m_path{};
std::unique_ptr<std::filesystem::directory_iterator> m_dirIterator{};
// serialization
FSC_ACCESS_FLAG m_accessFlags;
};
5 changes: 5 additions & 0 deletions src/Cafe/Filesystem/fscDeviceWua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/Cafe/Filesystem/fscDeviceWud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
51 changes: 51 additions & 0 deletions src/Cafe/HW/MMU/MMU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 12 additions & 5 deletions src/Cafe/HW/MMU/MMU.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include "util/helpers/Serializer.h"

void memory_init();
void memory_mapForCurrentTitle();
void memory_unmapForCurrentTitle();
Expand Down Expand Up @@ -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;
};


Expand Down Expand Up @@ -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)
{
Expand Down
Loading