156 changes: 83 additions & 73 deletions Source/Core/Core/IOS/ES/ES.cpp

Large diffs are not rendered by default.

135 changes: 82 additions & 53 deletions Source/Core/Core/IOS/ES/ES.h
Expand Up @@ -37,22 +37,17 @@ struct TitleContext
bool first_change = true;
};

class ESDevice final : public Device
class ESDevice;

class ESCore final
{
public:
ESDevice(Kernel& ios, const std::string& device_name);

static void InitializeEmulationState();
static void FinalizeEmulationState();

ReturnCode DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& ticket);
bool LaunchTitle(u64 title_id, HangPPC hang_ppc = HangPPC::No);

void DoState(PointerWrap& p) override;

std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
explicit ESCore(Kernel& ios);
ESCore(const ESCore& other) = delete;
ESCore(ESCore&& other) = delete;
ESCore& operator=(const ESCore& other) = delete;
ESCore& operator=(ESCore&& other) = delete;
~ESCore();

struct TitleImportExportContext
{
Expand Down Expand Up @@ -83,12 +78,6 @@ class ESDevice final : public Device
s32 ipc_fd = -1;
};

enum class CheckContentHashes : bool
{
Yes = true,
No = false,
};

ES::TMDReader FindImportTMD(u64 title_id, Ticks ticks = {}) const;
ES::TMDReader FindInstalledTMD(u64 title_id, Ticks ticks = {}) const;
ES::TicketReader FindSignedTicket(u64 title_id,
Expand All @@ -101,6 +90,12 @@ class ESDevice final : public Device
// Get titles for which there is a ticket (in /ticket).
std::vector<u64> GetTitlesWithTickets() const;

enum class CheckContentHashes : bool
{
Yes = true,
No = false,
};

std::vector<ES::Content>
GetStoredContentsFromTMD(const ES::TMDReader& tmd,
CheckContentHashes check_content_hashes = CheckContentHashes::No) const;
Expand Down Expand Up @@ -186,6 +181,71 @@ class ESDevice final : public Device
const ES::CertReader& certificate, const std::vector<u8>& cert_chain,
u32 certificate_iosc_handle);

private:
// Start a title import.
bool InitImport(const ES::TMDReader& tmd);
// Clean up the import content directory and move it back to /title.
bool FinishImport(const ES::TMDReader& tmd);
// Write a TMD for a title in /import atomically.
bool WriteImportTMD(const ES::TMDReader& tmd);
// Finish stale imports and clear the import directory.
void FinishStaleImport(u64 title_id);
void FinishAllStaleImports();

std::string GetContentPath(u64 title_id, const ES::Content& content, Ticks ticks = {}) const;

bool IsActiveTitlePermittedByTicket(const u8* ticket_view) const;

bool IsIssuerCorrect(VerifyContainerType type, const ES::CertReader& issuer_cert) const;
ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
ReturnCode WriteNewCertToStore(const ES::CertReader& cert);

ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view,
const ES::TMDReader& tmd) const;

struct OpenedContent
{
bool m_opened = false;
u64 m_fd = 0;
u64 m_title_id = 0;
ES::Content m_content{};
u32 m_uid = 0;
};

Kernel& m_ios;

using ContentTable = std::array<OpenedContent, 16>;
ContentTable m_content_table;

TitleContext m_title_context{};

friend class ESDevice;
};

class ESDevice final : public EmulationDevice
{
public:
ESDevice(EmulationKernel& ios, ESCore& core, const std::string& device_name);
ESDevice(const ESDevice& other) = delete;
ESDevice(ESDevice&& other) = delete;
ESDevice& operator=(const ESDevice& other) = delete;
ESDevice& operator=(ESDevice&& other) = delete;
~ESDevice();

static void InitializeEmulationState();
static void FinalizeEmulationState();

ReturnCode DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& ticket);
bool LaunchTitle(u64 title_id, HangPPC hang_ppc = HangPPC::No);

void DoState(PointerWrap& p) override;

std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;

ESCore& GetCore() const { return m_core; }

private:
enum
{
Expand Down Expand Up @@ -261,6 +321,7 @@ class ESDevice final : public Device
};

// ES can only have 3 contexts at one time.
using Context = ESCore::Context;
using ContextArray = std::array<Context, 3>;

// Title management
Expand Down Expand Up @@ -348,47 +409,15 @@ class ESDevice final : public Device

bool LaunchIOS(u64 ios_title_id, HangPPC hang_ppc);
bool LaunchPPCTitle(u64 title_id);
bool IsActiveTitlePermittedByTicket(const u8* ticket_view) const;

ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view,
const ES::TMDReader& tmd) const;

bool IsIssuerCorrect(VerifyContainerType type, const ES::CertReader& issuer_cert) const;
ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
ReturnCode WriteNewCertToStore(const ES::CertReader& cert);

// Start a title import.
bool InitImport(const ES::TMDReader& tmd);
// Clean up the import content directory and move it back to /title.
bool FinishImport(const ES::TMDReader& tmd);
// Write a TMD for a title in /import atomically.
bool WriteImportTMD(const ES::TMDReader& tmd);
// Finish stale imports and clear the import directory.
void FinishStaleImport(u64 title_id);
void FinishAllStaleImports();

void FinishInit();

std::string GetContentPath(u64 title_id, const ES::Content& content, Ticks ticks = {}) const;

s32 WriteSystemFile(const std::string& path, const std::vector<u8>& data, Ticks ticks = {});
s32 WriteLaunchFile(const ES::TMDReader& tmd, Ticks ticks = {});
bool BootstrapPPC();

struct OpenedContent
{
bool m_opened = false;
u64 m_fd = 0;
u64 m_title_id = 0;
ES::Content m_content{};
u32 m_uid = 0;
};

using ContentTable = std::array<OpenedContent, 16>;
ContentTable m_content_table;

ESCore& m_core;
ContextArray m_contexts;
TitleContext m_title_context{};
std::string m_pending_ppc_boot_content_path;
};
} // namespace IOS::HLE
15 changes: 7 additions & 8 deletions Source/Core/Core/IOS/ES/Formats.cpp
Expand Up @@ -554,17 +554,16 @@ struct SharedContentMap::Entry
};

constexpr char CONTENT_MAP_PATH[] = "/shared1/content.map";
SharedContentMap::SharedContentMap(std::shared_ptr<HLE::FSDevice> fs)
: m_fs_device{fs}, m_fs{fs->GetFS()}
SharedContentMap::SharedContentMap(HLE::FSCore& fs_core) : m_fs_core{fs_core}, m_fs{fs_core.GetFS()}
{
static_assert(sizeof(Entry) == 28, "SharedContentMap::Entry has the wrong size");

Entry entry;
const auto fd =
fs->Open(PID_KERNEL, PID_KERNEL, CONTENT_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
fs_core.Open(PID_KERNEL, PID_KERNEL, CONTENT_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
if (fd.Get() < 0)
return;
while (fs->Read(fd.Get(), &entry, 1, &m_ticks) == sizeof(entry))
while (fs_core.Read(fd.Get(), &entry, 1, &m_ticks) == sizeof(entry))
{
m_entries.push_back(entry);
m_last_id++;
Expand Down Expand Up @@ -637,7 +636,7 @@ bool SharedContentMap::WriteEntries() const
HLE::FS::ResultCode::Success;
}

static std::pair<u32, u64> ReadUidSysEntry(HLE::FSDevice& fs, u64 fd, u64* ticks)
static std::pair<u32, u64> ReadUidSysEntry(HLE::FSCore& fs, u64 fd, u64* ticks)
{
u64 title_id = 0;
if (fs.Read(fd, &title_id, 1, ticks) != sizeof(title_id))
Expand All @@ -651,15 +650,15 @@ static std::pair<u32, u64> ReadUidSysEntry(HLE::FSDevice& fs, u64 fd, u64* ticks
}

constexpr char UID_MAP_PATH[] = "/sys/uid.sys";
UIDSys::UIDSys(std::shared_ptr<HLE::FSDevice> fs) : m_fs_device{fs}, m_fs{fs->GetFS()}
UIDSys::UIDSys(HLE::FSCore& fs_core) : m_fs_core{fs_core}, m_fs{fs_core.GetFS()}
{
if (const auto fd =
fs->Open(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
fs_core.Open(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
fd.Get() >= 0)
{
while (true)
{
std::pair<u32, u64> entry = ReadUidSysEntry(*fs, fd.Get(), &m_ticks);
std::pair<u32, u64> entry = ReadUidSysEntry(fs_core, fd.Get(), &m_ticks);
if (!entry.first && !entry.second)
break;

Expand Down
8 changes: 4 additions & 4 deletions Source/Core/Core/IOS/ES/Formats.h
Expand Up @@ -280,7 +280,7 @@ class TicketReader final : public SignedBlobReader
class SharedContentMap final
{
public:
explicit SharedContentMap(std::shared_ptr<HLE::FSDevice> fs);
explicit SharedContentMap(HLE::FSCore& fs_core);
~SharedContentMap();

std::optional<std::string> GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const;
Expand All @@ -296,15 +296,15 @@ class SharedContentMap final
struct Entry;
u32 m_last_id = 0;
std::vector<Entry> m_entries;
std::shared_ptr<HLE::FSDevice> m_fs_device;
HLE::FSCore& m_fs_core;
std::shared_ptr<HLE::FS::FileSystem> m_fs;
u64 m_ticks = 0;
};

class UIDSys final
{
public:
explicit UIDSys(std::shared_ptr<HLE::FSDevice> fs);
explicit UIDSys(HLE::FSCore& fs_core);

u32 GetUIDFromTitle(u64 title_id) const;
u32 GetOrInsertUIDForTitle(u64 title_id);
Expand All @@ -313,7 +313,7 @@ class UIDSys final
u64 GetTicks() const { return m_ticks; }

private:
std::shared_ptr<HLE::FSDevice> m_fs_device;
HLE::FSCore& m_fs_core;
std::shared_ptr<HLE::FS::FileSystem> m_fs;
std::map<u32, u64> m_entries;
u64 m_ticks = 0;
Expand Down
35 changes: 19 additions & 16 deletions Source/Core/Core/IOS/ES/Identity.cpp
Expand Up @@ -19,7 +19,7 @@

namespace IOS::HLE
{
ReturnCode ESDevice::GetDeviceId(u32* device_id) const
ReturnCode ESCore::GetDeviceId(u32* device_id) const
{
*device_id = m_ios.GetIOSC().GetDeviceId();
INFO_LOG_FMT(IOS_ES, "GetDeviceId: {:08X}", *device_id);
Expand All @@ -32,11 +32,11 @@ IPCReply ESDevice::GetDeviceId(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);

u32 device_id;
const ReturnCode ret = GetDeviceId(&device_id);
const ReturnCode ret = m_core.GetDeviceId(&device_id);
if (ret != IPC_SUCCESS)
return IPCReply(ret);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(device_id, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
Expand All @@ -47,7 +47,7 @@ IPCReply ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(3, 2))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 keyIndex = memory.Read_U32(request.in_vectors[0].address);
u8* source = memory.GetPointer(request.in_vectors[2].address);
Expand All @@ -57,7 +57,8 @@ IPCReply ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)

// TODO: Check whether the active title is allowed to encrypt.

const ReturnCode ret = m_ios.GetIOSC().Encrypt(keyIndex, iv, source, size, destination, PID_ES);
const ReturnCode ret =
GetEmulationKernel().GetIOSC().Encrypt(keyIndex, iv, source, size, destination, PID_ES);
return IPCReply(ret);
}

Expand All @@ -66,7 +67,7 @@ IPCReply ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(3, 2))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u32 keyIndex = memory.Read_U32(request.in_vectors[0].address);
u8* source = memory.GetPointer(request.in_vectors[2].address);
Expand All @@ -76,7 +77,8 @@ IPCReply ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)

// TODO: Check whether the active title is allowed to decrypt.

const ReturnCode ret = m_ios.GetIOSC().Decrypt(keyIndex, iv, source, size, destination, PID_ES);
const ReturnCode ret =
GetEmulationKernel().GetIOSC().Decrypt(keyIndex, iv, source, size, destination, PID_ES);
return IPCReply(ret);
}

Expand All @@ -100,9 +102,9 @@ IPCReply ESDevice::GetDeviceCertificate(const IOCtlVRequest& request)

INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETDEVICECERT");

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const IOS::CertECC cert = m_ios.GetIOSC().GetDeviceCertificate();
const IOS::CertECC cert = GetEmulationKernel().GetIOSC().GetDeviceCertificate();
memory.CopyToEmu(request.io_vectors[0].address, &cert, sizeof(cert));
return IPCReply(IPC_SUCCESS);
}
Expand All @@ -113,22 +115,23 @@ IPCReply ESDevice::Sign(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);

INFO_LOG_FMT(IOS_ES, "IOCTL_ES_SIGN");
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
u8* ap_cert_out = memory.GetPointer(request.io_vectors[1].address);
u8* data = memory.GetPointer(request.in_vectors[0].address);
u32 data_size = request.in_vectors[0].size;
u8* sig_out = memory.GetPointer(request.io_vectors[0].address);

if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);

m_ios.GetIOSC().Sign(sig_out, ap_cert_out, m_title_context.tmd.GetTitleId(), data, data_size);
GetEmulationKernel().GetIOSC().Sign(sig_out, ap_cert_out, m_core.m_title_context.tmd.GetTitleId(),
data, data_size);
return IPCReply(IPC_SUCCESS);
}

ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
const std::vector<u8>& certs_bytes)
ReturnCode ESCore::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
const std::vector<u8>& certs_bytes)
{
const std::map<std::string, ES::CertReader> certs = ES::ParseCertChain(certs_bytes);
if (certs.empty())
Expand Down Expand Up @@ -205,7 +208,7 @@ IPCReply ESDevice::VerifySign(const IOCtlVRequest& request)
if (request.in_vectors[1].size != sizeof(Common::ec::Signature))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

std::vector<u8> hash(request.in_vectors[0].size);
Expand All @@ -217,6 +220,6 @@ IPCReply ESDevice::VerifySign(const IOCtlVRequest& request)
std::vector<u8> certs(request.in_vectors[2].size);
memory.CopyFromEmu(certs.data(), request.in_vectors[2].address, certs.size());

return IPCReply(VerifySign(hash, ecc_signature, certs));
return IPCReply(m_core.VerifySign(hash, ecc_signature, certs));
}
} // namespace IOS::HLE
50 changes: 25 additions & 25 deletions Source/Core/Core/IOS/ES/NandUtils.cpp
Expand Up @@ -25,7 +25,7 @@

namespace IOS::HLE
{
static ES::TMDReader FindTMD(FSDevice& fs, const std::string& tmd_path, Ticks ticks)
static ES::TMDReader FindTMD(FSCore& fs, const std::string& tmd_path, Ticks ticks)
{
const auto fd = fs.Open(PID_KERNEL, PID_KERNEL, tmd_path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
Expand All @@ -38,18 +38,18 @@ static ES::TMDReader FindTMD(FSDevice& fs, const std::string& tmd_path, Ticks ti
return ES::TMDReader{std::move(tmd_bytes)};
}

ES::TMDReader ESDevice::FindImportTMD(u64 title_id, Ticks ticks) const
ES::TMDReader ESCore::FindImportTMD(u64 title_id, Ticks ticks) const
{
return FindTMD(*m_ios.GetFSDevice(), Common::GetImportTitlePath(title_id) + "/content/title.tmd",
return FindTMD(m_ios.GetFSCore(), Common::GetImportTitlePath(title_id) + "/content/title.tmd",
ticks);
}

ES::TMDReader ESDevice::FindInstalledTMD(u64 title_id, Ticks ticks) const
ES::TMDReader ESCore::FindInstalledTMD(u64 title_id, Ticks ticks) const
{
return FindTMD(*m_ios.GetFSDevice(), Common::GetTMDFileName(title_id), ticks);
return FindTMD(m_ios.GetFSCore(), Common::GetTMDFileName(title_id), ticks);
}

ES::TicketReader ESDevice::FindSignedTicket(u64 title_id, std::optional<u8> desired_version) const
ES::TicketReader ESCore::FindSignedTicket(u64 title_id, std::optional<u8> desired_version) const
{
std::string path = desired_version == 1 ? Common::GetV1TicketFileName(title_id) :
Common::GetTicketFileName(title_id);
Expand Down Expand Up @@ -125,17 +125,17 @@ static std::vector<u64> GetTitlesInTitleOrImport(FS::FileSystem* fs, const std::
return title_ids;
}

std::vector<u64> ESDevice::GetInstalledTitles() const
std::vector<u64> ESCore::GetInstalledTitles() const
{
return GetTitlesInTitleOrImport(m_ios.GetFS().get(), "/title");
}

std::vector<u64> ESDevice::GetTitleImports() const
std::vector<u64> ESCore::GetTitleImports() const
{
return GetTitlesInTitleOrImport(m_ios.GetFS().get(), "/import");
}

std::vector<u64> ESDevice::GetTitlesWithTickets() const
std::vector<u64> ESCore::GetTitlesWithTickets() const
{
const auto fs = m_ios.GetFS();
const auto entries = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, "/ticket");
Expand Down Expand Up @@ -179,8 +179,8 @@ std::vector<u64> ESDevice::GetTitlesWithTickets() const
}

std::vector<ES::Content>
ESDevice::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
CheckContentHashes check_content_hashes) const
ESCore::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
CheckContentHashes check_content_hashes) const
{
if (!tmd.IsValid())
return {};
Expand Down Expand Up @@ -216,7 +216,7 @@ ESDevice::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
return stored_contents;
}

u32 ESDevice::GetSharedContentsCount() const
u32 ESCore::GetSharedContentsCount() const
{
const auto entries = m_ios.GetFS()->ReadDirectory(PID_KERNEL, PID_KERNEL, "/shared1");
return static_cast<u32>(
Expand All @@ -226,9 +226,9 @@ u32 ESDevice::GetSharedContentsCount() const
}));
}

std::vector<std::array<u8, 20>> ESDevice::GetSharedContents() const
std::vector<std::array<u8, 20>> ESCore::GetSharedContents() const
{
const ES::SharedContentMap map{m_ios.GetFSDevice()};
const ES::SharedContentMap map{m_ios.GetFSCore()};
return map.GetHashes();
}

Expand All @@ -253,7 +253,7 @@ constexpr FS::Modes title_dir_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS
constexpr FS::Modes content_dir_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None};
constexpr FS::Modes data_dir_modes{FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None};

bool ESDevice::CreateTitleDirectories(u64 title_id, u16 group_id) const
bool ESCore::CreateTitleDirectories(u64 title_id, u16 group_id) const
{
const auto fs = m_ios.GetFS();

Expand All @@ -278,7 +278,7 @@ bool ESDevice::CreateTitleDirectories(u64 title_id, u16 group_id) const
return false;
}

ES::UIDSys uid_sys{m_ios.GetFSDevice()};
ES::UIDSys uid_sys{m_ios.GetFSCore()};
const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id);
if (fs->SetMetadata(0, data_dir, uid, group_id, 0, data_dir_modes) != FS::ResultCode::Success)
{
Expand All @@ -289,7 +289,7 @@ bool ESDevice::CreateTitleDirectories(u64 title_id, u16 group_id) const
return true;
}

bool ESDevice::InitImport(const ES::TMDReader& tmd)
bool ESCore::InitImport(const ES::TMDReader& tmd)
{
if (!CreateTitleDirectories(tmd.GetTitleId(), tmd.GetGroupId()))
return false;
Expand Down Expand Up @@ -321,7 +321,7 @@ bool ESDevice::InitImport(const ES::TMDReader& tmd)
return true;
}

bool ESDevice::FinishImport(const ES::TMDReader& tmd)
bool ESCore::FinishImport(const ES::TMDReader& tmd)
{
const auto fs = m_ios.GetFS();
const u64 title_id = tmd.GetTitleId();
Expand Down Expand Up @@ -354,7 +354,7 @@ bool ESDevice::FinishImport(const ES::TMDReader& tmd)
return true;
}

bool ESDevice::WriteImportTMD(const ES::TMDReader& tmd)
bool ESCore::WriteImportTMD(const ES::TMDReader& tmd)
{
const auto fs = m_ios.GetFS();
const std::string tmd_path = "/tmp/title.tmd";
Expand All @@ -369,7 +369,7 @@ bool ESDevice::WriteImportTMD(const ES::TMDReader& tmd)
return fs->Rename(PID_KERNEL, PID_KERNEL, tmd_path, dest) == FS::ResultCode::Success;
}

void ESDevice::FinishStaleImport(u64 title_id)
void ESCore::FinishStaleImport(u64 title_id)
{
const auto fs = m_ios.GetFS();
const auto import_tmd = FindImportTMD(title_id);
Expand All @@ -385,19 +385,19 @@ void ESDevice::FinishStaleImport(u64 title_id)
}
}

void ESDevice::FinishAllStaleImports()
void ESCore::FinishAllStaleImports()
{
const std::vector<u64> titles = GetTitleImports();
for (const u64& title_id : titles)
FinishStaleImport(title_id);
}

std::string ESDevice::GetContentPath(const u64 title_id, const ES::Content& content,
Ticks ticks) const
std::string ESCore::GetContentPath(const u64 title_id, const ES::Content& content,
Ticks ticks) const
{
if (content.IsShared())
{
ES::SharedContentMap content_map{m_ios.GetFSDevice()};
ES::SharedContentMap content_map{m_ios.GetFSCore()};
ticks.Add(content_map.GetTicks());
return content_map.GetFilenameFromSHA1(content.sha1).value_or("");
}
Expand All @@ -406,7 +406,7 @@ std::string ESDevice::GetContentPath(const u64 title_id, const ES::Content& cont

s32 ESDevice::WriteSystemFile(const std::string& path, const std::vector<u8>& data, Ticks ticks)
{
auto& fs = *m_ios.GetFSDevice();
auto& fs = GetEmulationKernel().GetFSCore();
const std::string tmp_path = "/tmp/" + PathToFileName(path);

auto result = fs.CreateFile(PID_KERNEL, PID_KERNEL, tmp_path, {},
Expand Down
44 changes: 22 additions & 22 deletions Source/Core/Core/IOS/ES/TitleContents.cpp
Expand Up @@ -14,7 +14,7 @@

namespace IOS::HLE
{
s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid, Ticks ticks)
s32 ESCore::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid, Ticks ticks)
{
const u64 title_id = tmd.GetTitleId();

Expand All @@ -29,7 +29,7 @@ s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid,
continue;

const std::string path = GetContentPath(title_id, content, ticks);
auto fd = m_ios.GetFSDevice()->Open(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read, {}, ticks);
auto fd = m_ios.GetFSCore().Open(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
return fd.Get();

Expand Down Expand Up @@ -57,17 +57,17 @@ IPCReply ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)
return ES_EINVAL;
}

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const u32 content_index = memory.Read_U32(request.in_vectors[2].address);
// TODO: check the ticket view, check permissions.

const auto tmd = FindInstalledTMD(title_id, ticks);
const auto tmd = m_core.FindInstalledTMD(title_id, ticks);
if (!tmd.IsValid())
return FS_ENOENT;

return OpenContent(tmd, content_index, uid, ticks);
return m_core.OpenContent(tmd, content_index, uid, ticks);
});
}

Expand All @@ -77,24 +77,24 @@ IPCReply ESDevice::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& r
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return ES_EINVAL;

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 content_index = memory.Read_U32(request.in_vectors[0].address);

if (!m_title_context.active)
if (!m_core.m_title_context.active)
return ES_EINVAL;

ES::UIDSys uid_map{m_ios.GetFSDevice()};
const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId());
ES::UIDSys uid_map{GetEmulationKernel().GetFSCore()};
const u32 uid = uid_map.GetOrInsertUIDForTitle(m_core.m_title_context.tmd.GetTitleId());
ticks.Add(uid_map.GetTicks());
if (caller_uid != 0 && caller_uid != uid)
return ES_EACCES;

return OpenContent(m_title_context.tmd, content_index, caller_uid, ticks);
return m_core.OpenContent(m_core.m_title_context.tmd, content_index, caller_uid, ticks);
});
}

s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks)
s32 ESCore::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks)
{
if (cfd >= m_content_table.size())
return ES_EINVAL;
Expand All @@ -105,7 +105,7 @@ s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks)
if (!entry.m_opened)
return IPC_EINVAL;

return m_ios.GetFSDevice()->Read(entry.m_fd, buffer, size, {}, ticks);
return m_ios.GetFSCore().Read(entry.m_fd, buffer, size, {}, ticks);
}

IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
Expand All @@ -114,19 +114,19 @@ IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return ES_EINVAL;

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 cfd = memory.Read_U32(request.in_vectors[0].address);
const u32 size = request.io_vectors[0].size;
const u32 addr = request.io_vectors[0].address;

INFO_LOG_FMT(IOS_ES, "ReadContent(uid={:#x}, cfd={}, size={}, addr={:08x})", uid, cfd, size,
addr);
return ReadContent(cfd, memory.GetPointer(addr), size, uid, ticks);
return m_core.ReadContent(cfd, memory.GetPointer(addr), size, uid, ticks);
});
}

s32 ESDevice::CloseContent(u32 cfd, u32 uid, Ticks ticks)
s32 ESCore::CloseContent(u32 cfd, u32 uid, Ticks ticks)
{
if (cfd >= m_content_table.size())
return ES_EINVAL;
Expand All @@ -137,7 +137,7 @@ s32 ESDevice::CloseContent(u32 cfd, u32 uid, Ticks ticks)
if (!entry.m_opened)
return IPC_EINVAL;

m_ios.GetFSDevice()->Close(entry.m_fd, ticks);
m_ios.GetFSCore().Close(entry.m_fd, ticks);
entry = {};
INFO_LOG_FMT(IOS_ES, "CloseContent: CFD {}", cfd);
return IPC_SUCCESS;
Expand All @@ -149,14 +149,14 @@ IPCReply ESDevice::CloseContent(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return ES_EINVAL;

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 cfd = memory.Read_U32(request.in_vectors[0].address);
return CloseContent(cfd, uid, ticks);
return m_core.CloseContent(cfd, uid, ticks);
});
}

s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks ticks)
s32 ESCore::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks ticks)
{
if (cfd >= m_content_table.size())
return ES_EINVAL;
Expand All @@ -167,7 +167,7 @@ s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks tic
if (!entry.m_opened)
return IPC_EINVAL;

return m_ios.GetFSDevice()->Seek(entry.m_fd, offset, static_cast<FS::SeekMode>(mode), ticks);
return m_ios.GetFSCore().Seek(entry.m_fd, offset, static_cast<FS::SeekMode>(mode), ticks);
}

IPCReply ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
Expand All @@ -176,13 +176,13 @@ IPCReply ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(3, 0))
return ES_EINVAL;

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 cfd = memory.Read_U32(request.in_vectors[0].address);
const u32 offset = memory.Read_U32(request.in_vectors[1].address);
const auto mode = static_cast<SeekMode>(memory.Read_U32(request.in_vectors[2].address));

return SeekContent(cfd, offset, mode, uid, ticks);
return m_core.SeekContent(cfd, offset, mode, uid, ticks);
});
}
} // namespace IOS::HLE
55 changes: 28 additions & 27 deletions Source/Core/Core/IOS/ES/TitleInformation.cpp
Expand Up @@ -21,8 +21,8 @@ IPCReply ESDevice::GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlV
if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid())
return IPCReply(ES_EINVAL);

const u16 num_contents = static_cast<u16>(GetStoredContentsFromTMD(tmd).size());
auto& system = Core::System::GetInstance();
const u16 num_contents = static_cast<u16>(m_core.GetStoredContentsFromTMD(tmd).size());
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(num_contents, request.io_vectors[0].address);

Expand All @@ -38,15 +38,15 @@ IPCReply ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOCtlVReque
if (!tmd.IsValid())
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
if (request.in_vectors[1].size != sizeof(u32) ||
request.io_vectors[0].size != memory.Read_U32(request.in_vectors[1].address) * sizeof(u32))
{
return IPCReply(ES_EINVAL);
}

const auto contents = GetStoredContentsFromTMD(tmd);
const auto contents = m_core.GetStoredContentsFromTMD(tmd);
const u32 max_content_count = memory.Read_U32(request.in_vectors[1].address);
for (u32 i = 0; i < std::min(static_cast<u32>(contents.size()), max_content_count); ++i)
memory.Write_U32(contents[i].id, request.io_vectors[0].address + i * sizeof(u32));
Expand All @@ -59,10 +59,10 @@ IPCReply ESDevice::GetStoredContentsCount(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u64))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
return GetStoredContentsCount(tmd, request);
Expand All @@ -73,10 +73,10 @@ IPCReply ESDevice::GetStoredContents(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
return GetStoredContents(tmd, request);
Expand All @@ -88,7 +88,7 @@ IPCReply ESDevice::GetTMDStoredContentsCount(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);

std::vector<u8> tmd_bytes(request.in_vectors[0].size);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
return GetStoredContentsCount(ES::TMDReader{std::move(tmd_bytes)}, request);
Expand All @@ -100,7 +100,7 @@ IPCReply ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);

std::vector<u8> tmd_bytes(request.in_vectors[0].size);
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());

Expand All @@ -109,11 +109,12 @@ IPCReply ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);

std::vector<u8> cert_store;
ReturnCode ret = ReadCertStore(&cert_store);
ReturnCode ret = m_core.ReadCertStore(&cert_store);
if (ret != IPC_SUCCESS)
return IPCReply(ret);

ret = VerifyContainer(VerifyContainerType::TMD, VerifyMode::UpdateCertStore, tmd, cert_store);
ret = m_core.VerifyContainer(ESCore::VerifyContainerType::TMD,
ESCore::VerifyMode::UpdateCertStore, tmd, cert_store);
if (ret != IPC_SUCCESS)
return IPCReply(ret);

Expand All @@ -125,7 +126,7 @@ IPCReply ESDevice::GetTitleCount(const std::vector<u64>& titles, const IOCtlVReq
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(static_cast<u32>(titles.size()), request.io_vectors[0].address);

Expand All @@ -137,7 +138,7 @@ IPCReply ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const size_t max_count = memory.Read_U32(request.in_vectors[0].address);
for (size_t i = 0; i < std::min(max_count, titles.size()); i++)
Expand All @@ -150,25 +151,25 @@ IPCReply ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest

IPCReply ESDevice::GetTitleCount(const IOCtlVRequest& request)
{
const std::vector<u64> titles = GetInstalledTitles();
const std::vector<u64> titles = m_core.GetInstalledTitles();
INFO_LOG_FMT(IOS_ES, "GetTitleCount: {} titles", titles.size());
return GetTitleCount(titles, request);
}

IPCReply ESDevice::GetTitles(const IOCtlVRequest& request)
{
return GetTitles(GetInstalledTitles(), request);
return GetTitles(m_core.GetInstalledTitles(), request);
}

IPCReply ESDevice::GetStoredTMDSize(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);

Expand All @@ -185,10 +186,10 @@ IPCReply ESDevice::GetStoredTMD(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 1))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);
if (!tmd.IsValid())
return IPCReply(FS_ENOENT);

Expand All @@ -207,14 +208,14 @@ IPCReply ESDevice::GetStoredTMD(const IOCtlVRequest& request)

IPCReply ESDevice::GetOwnedTitleCount(const IOCtlVRequest& request)
{
const std::vector<u64> titles = GetTitlesWithTickets();
const std::vector<u64> titles = m_core.GetTitlesWithTickets();
INFO_LOG_FMT(IOS_ES, "GetOwnedTitleCount: {} titles", titles.size());
return GetTitleCount(titles, request);
}

IPCReply ESDevice::GetOwnedTitles(const IOCtlVRequest& request)
{
return GetTitles(GetTitlesWithTickets(), request);
return GetTitles(m_core.GetTitlesWithTickets(), request);
}

IPCReply ESDevice::GetBoot2Version(const IOCtlVRequest& request)
Expand All @@ -225,7 +226,7 @@ IPCReply ESDevice::GetBoot2Version(const IOCtlVRequest& request)
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETBOOT2VERSION");

// as of 26/02/2012, this was latest bootmii version
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(4, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
Expand All @@ -236,8 +237,8 @@ IPCReply ESDevice::GetSharedContentsCount(const IOCtlVRequest& request) const
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);

const u32 count = GetSharedContentsCount();
auto& system = Core::System::GetInstance();
const u32 count = m_core.GetSharedContentsCount();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(count, request.io_vectors[0].address);

Expand All @@ -250,13 +251,13 @@ IPCReply ESDevice::GetSharedContents(const IOCtlVRequest& request) const
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const u32 max_count = memory.Read_U32(request.in_vectors[0].address);
if (request.io_vectors[0].size != 20 * max_count)
return IPCReply(ES_EINVAL);

const std::vector<std::array<u8, 20>> hashes = GetSharedContents();
const std::vector<std::array<u8, 20>> hashes = m_core.GetSharedContents();
const u32 count = std::min(static_cast<u32>(hashes.size()), max_count);
memory.CopyToEmu(request.io_vectors[0].address, hashes.data(), 20 * count);

Expand Down
135 changes: 68 additions & 67 deletions Source/Core/Core/IOS/ES/TitleManagement.cpp

Large diffs are not rendered by default.

75 changes: 38 additions & 37 deletions Source/Core/Core/IOS/ES/Views.cpp
Expand Up @@ -41,20 +41,20 @@ IPCReply ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const u64 TitleID = memory.Read_U64(request.in_vectors[0].address);

const ES::TicketReader ticket = FindSignedTicket(TitleID);
const ES::TicketReader ticket = m_core.FindSignedTicket(TitleID);
u32 view_count = ticket.IsValid() ? static_cast<u32>(ticket.GetNumberOfTickets()) : 0;

if (!IsEmulated(TitleID))
{
view_count = 0;
ERROR_LOG_FMT(IOS_ES, "GetViewCount: Dolphin doesn't emulate IOS title {:016x}", TitleID);
}
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_title_context))
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_core.m_title_context))
{
view_count = 1;
WARN_LOG_FMT(IOS_ES, "GetViewCount: Faking IOS title {:016x} being present", TitleID);
Expand All @@ -72,13 +72,13 @@ IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(2, 1))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const u64 TitleID = memory.Read_U64(request.in_vectors[0].address);
const u32 maxViews = memory.Read_U32(request.in_vectors[1].address);

const ES::TicketReader ticket = FindSignedTicket(TitleID);
const ES::TicketReader ticket = m_core.FindSignedTicket(TitleID);

if (!IsEmulated(TitleID))
{
Expand All @@ -94,7 +94,7 @@ IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
ticket_view.data(), ticket_view.size());
}
}
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_title_context))
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_core.m_title_context))
{
memory.Memset(request.io_vectors[0].address, 0, sizeof(ES::TicketView));
WARN_LOG_FMT(IOS_ES, "GetViews: Faking IOS title {:016x} being present", TitleID);
Expand All @@ -105,8 +105,8 @@ IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
return IPCReply(IPC_SUCCESS);
}

ReturnCode ESDevice::GetTicketFromView(const u8* ticket_view, u8* ticket, u32* ticket_size,
std::optional<u8> desired_version) const
ReturnCode ESCore::GetTicketFromView(const u8* ticket_view, u8* ticket, u32* ticket_size,
std::optional<u8> desired_version) const
{
const u64 title_id = Common::swap64(&ticket_view[offsetof(ES::TicketView, title_id)]);
const u64 ticket_id = Common::swap64(&ticket_view[offsetof(ES::TicketView, ticket_id)]);
Expand Down Expand Up @@ -160,10 +160,11 @@ IPCReply ESDevice::GetV0TicketFromView(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return IPCReply(GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address), nullptr, 0));
return IPCReply(m_core.GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address),
nullptr, 0));
}

IPCReply ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
Expand All @@ -176,10 +177,10 @@ IPCReply ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
const ReturnCode ret = GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
nullptr, &ticket_size, std::nullopt);
const ReturnCode ret = m_core.GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
nullptr, &ticket_size, std::nullopt);
memory.Write_U32(ticket_size, request.io_vectors[0].address);
return IPCReply(ret);
}
Expand All @@ -193,28 +194,28 @@ IPCReply ESDevice::GetTicketFromView(const IOCtlVRequest& request)
return IPCReply(ES_EINVAL);
}

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

u32 ticket_size = memory.Read_U32(request.in_vectors[1].address);
if (ticket_size != request.io_vectors[0].size)
return IPCReply(ES_EINVAL);

return IPCReply(GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address), &ticket_size,
std::nullopt));
return IPCReply(m_core.GetTicketFromView(memory.GetPointer(request.in_vectors[0].address),
memory.GetPointer(request.io_vectors[0].address),
&ticket_size, std::nullopt));
}

IPCReply ESDevice::GetTMDViewSize(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const u64 TitleID = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(TitleID);
const ES::TMDReader tmd = m_core.FindInstalledTMD(TitleID);

if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
Expand All @@ -228,7 +229,7 @@ IPCReply ESDevice::GetTMDViewSize(const IOCtlVRequest& request)

IPCReply ESDevice::GetTMDViews(const IOCtlVRequest& request)
{
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

if (!request.HasNumberOfValidVectors(2, 1) ||
Expand All @@ -240,7 +241,7 @@ IPCReply ESDevice::GetTMDViews(const IOCtlVRequest& request)
}

const u64 title_id = memory.Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
const ES::TMDReader tmd = m_core.FindInstalledTMD(title_id);

if (!tmd.IsValid())
return IPCReply(FS_ENOENT);
Expand All @@ -267,7 +268,7 @@ IPCReply ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
if (request.io_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const bool has_tmd = request.in_vectors[0].size != 0;
Expand All @@ -289,10 +290,10 @@ IPCReply ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
else
{
// If no TMD was passed in and no title is active, IOS returns -1017.
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);

tmd_view_size = m_title_context.tmd.GetRawView().size();
tmd_view_size = m_core.m_title_context.tmd.GetRawView().size();
}

memory.Write_U32(static_cast<u32>(tmd_view_size), request.io_vectors[0].address);
Expand All @@ -308,7 +309,7 @@ IPCReply ESDevice::DIGetTMDView(const IOCtlVRequest& request)
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

// Check whether the TMD view size is consistent.
Expand All @@ -335,10 +336,10 @@ IPCReply ESDevice::DIGetTMDView(const IOCtlVRequest& request)
else
{
// If no TMD was passed in and no title is active, IOS returns -1017.
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);

tmd_view = m_title_context.tmd.GetRawView();
tmd_view = m_core.m_title_context.tmd.GetRawView();
}

if (tmd_view.size() > request.io_vectors[0].size)
Expand All @@ -362,7 +363,7 @@ IPCReply ESDevice::DIGetTicketView(const IOCtlVRequest& request)
if (!has_ticket_vector && request.in_vectors[0].size != 0)
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

std::vector<u8> view;
Expand All @@ -371,10 +372,10 @@ IPCReply ESDevice::DIGetTicketView(const IOCtlVRequest& request)
// Of course, this returns -1017 if no title is active and no ticket is passed.
if (!has_ticket_vector)
{
if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);

view = m_title_context.ticket.GetRawTicketView(0);
view = m_core.m_title_context.ticket.GetRawTicketView(0);
}
else
{
Expand All @@ -394,12 +395,12 @@ IPCReply ESDevice::DIGetTMDSize(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);

if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
memory.Write_U32(static_cast<u32>(m_title_context.tmd.GetBytes().size()),
memory.Write_U32(static_cast<u32>(m_core.m_title_context.tmd.GetBytes().size()),
request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
}
Expand All @@ -409,17 +410,17 @@ IPCReply ESDevice::DIGetTMD(const IOCtlVRequest& request)
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return IPCReply(ES_EINVAL);

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const u32 tmd_size = memory.Read_U32(request.in_vectors[0].address);
if (tmd_size != request.io_vectors[0].size)
return IPCReply(ES_EINVAL);

if (!m_title_context.active)
if (!m_core.m_title_context.active)
return IPCReply(ES_EINVAL);

const std::vector<u8>& tmd_bytes = m_title_context.tmd.GetBytes();
const std::vector<u8>& tmd_bytes = m_core.m_title_context.tmd.GetBytes();

if (static_cast<u32>(tmd_bytes.size()) > tmd_size)
return IPCReply(ES_EINVAL);
Expand Down
121 changes: 65 additions & 56 deletions Source/Core/Core/IOS/FS/FileSystemProxy.cpp
Expand Up @@ -83,7 +83,7 @@ constexpr SystemTimers::TimeBaseTick GetFreeClusterCheckTbTicks()

constexpr size_t CLUSTER_DATA_SIZE = 0x4000;

FSDevice::FSDevice(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
FSCore::FSCore(Kernel& ios) : m_ios(ios)
{
if (ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, "/tmp") == ResultCode::Success)
{
Expand All @@ -92,14 +92,23 @@ FSDevice::FSDevice(Kernel& ios, const std::string& device_name) : Device(ios, de
}
}

FSCore::~FSCore() = default;

FSDevice::FSDevice(EmulationKernel& ios, FSCore& core, const std::string& device_name)
: EmulationDevice(ios, device_name), m_core(core)
{
}

FSDevice::~FSDevice() = default;

void FSDevice::DoState(PointerWrap& p)
{
Device::DoState(p);
p.Do(m_dirty_cache);
p.Do(m_cache_chain_index);
p.Do(m_cache_fd);
p.Do(m_next_fd);
p.Do(m_fd_map);
p.Do(m_core.m_dirty_cache);
p.Do(m_core.m_cache_chain_index);
p.Do(m_core.m_cache_fd);
p.Do(m_core.m_next_fd);
p.Do(m_core.m_fd_map);
}

template <typename... Args>
Expand Down Expand Up @@ -161,14 +170,15 @@ static IPCReply GetReplyForSuperblockOperation(int ios_version, ResultCode resul
std::optional<IPCReply> FSDevice::Open(const OpenRequest& request)
{
return MakeIPCReply([&](Ticks t) {
return Open(request.uid, request.gid, request.path, static_cast<Mode>(request.flags & 3),
request.fd, t)
return m_core
.Open(request.uid, request.gid, request.path, static_cast<Mode>(request.flags & 3),
request.fd, t)
.Release();
});
}

FSDevice::ScopedFd FSDevice::Open(FS::Uid uid, FS::Gid gid, const std::string& path, FS::Mode mode,
std::optional<u32> ipc_fd, Ticks ticks)
FSCore::ScopedFd FSCore::Open(FS::Uid uid, FS::Gid gid, const std::string& path, FS::Mode mode,
std::optional<u32> ipc_fd, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand Down Expand Up @@ -200,10 +210,10 @@ FSDevice::ScopedFd FSDevice::Open(FS::Uid uid, FS::Gid gid, const std::string& p

std::optional<IPCReply> FSDevice::Close(u32 fd)
{
return MakeIPCReply([&](Ticks t) { return Close(static_cast<u64>(fd), t); });
return MakeIPCReply([&](Ticks t) { return m_core.Close(static_cast<u64>(fd), t); });
}

s32 FSDevice::Close(u64 fd, Ticks ticks)
s32 FSCore::Close(u64 fd, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand Down Expand Up @@ -232,7 +242,7 @@ s32 FSDevice::Close(u64 fd, Ticks ticks)
return IPC_SUCCESS;
}

u64 FSDevice::SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size)
u64 FSCore::SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size)
{
if (HasCacheForFile(fd, offset))
return 0;
Expand All @@ -246,7 +256,7 @@ u64 FSDevice::SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size)
return ticks;
}

u64 FSDevice::SimulateFlushFileCache()
u64 FSCore::SimulateFlushFileCache()
{
if (!m_cache_fd.has_value() || !m_dirty_cache)
return 0;
Expand All @@ -256,8 +266,8 @@ u64 FSDevice::SimulateFlushFileCache()
}

// Simulate parts of the FS read/write logic to estimate ticks for file operations correctly.
u64 FSDevice::EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command,
u32 size)
u64 FSCore::EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command,
u32 size)
{
u64 ticks = 0;

Expand Down Expand Up @@ -304,7 +314,7 @@ u64 FSDevice::EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommand
return ticks;
}

bool FSDevice::HasCacheForFile(u64 fd, u32 offset) const
bool FSCore::HasCacheForFile(u64 fd, u32 offset) const
{
const u16 chain_index = static_cast<u16>(offset / CLUSTER_DATA_SIZE);
return m_cache_fd == fd && m_cache_chain_index == chain_index;
Expand All @@ -313,13 +323,14 @@ bool FSDevice::HasCacheForFile(u64 fd, u32 offset) const
std::optional<IPCReply> FSDevice::Read(const ReadWriteRequest& request)
{
return MakeIPCReply([&](Ticks t) {
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return Read(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer, t);
return m_core.Read(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer,
t);
});
}

s32 FSDevice::Read(u64 fd, u8* data, u32 size, std::optional<u32> ipc_buffer_addr, Ticks ticks)
s32 FSCore::Read(u64 fd, u8* data, u32 size, std::optional<u32> ipc_buffer_addr, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand All @@ -343,14 +354,14 @@ s32 FSDevice::Read(u64 fd, u8* data, u32 size, std::optional<u32> ipc_buffer_add
std::optional<IPCReply> FSDevice::Write(const ReadWriteRequest& request)
{
return MakeIPCReply([&](Ticks t) {
auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();
return Write(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer, t);
return m_core.Write(request.fd, memory.GetPointer(request.buffer), request.size, request.buffer,
t);
});
}

s32 FSDevice::Write(u64 fd, const u8* data, u32 size, std::optional<u32> ipc_buffer_addr,
Ticks ticks)
s32 FSCore::Write(u64 fd, const u8* data, u32 size, std::optional<u32> ipc_buffer_addr, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand All @@ -374,11 +385,11 @@ s32 FSDevice::Write(u64 fd, const u8* data, u32 size, std::optional<u32> ipc_buf
std::optional<IPCReply> FSDevice::Seek(const SeekRequest& request)
{
return MakeIPCReply([&](Ticks t) {
return Seek(request.fd, request.offset, HLE::FS::SeekMode(request.mode), t);
return m_core.Seek(request.fd, request.offset, HLE::FS::SeekMode(request.mode), t);
});
}

s32 FSDevice::Seek(u64 fd, u32 offset, FS::SeekMode mode, Ticks ticks)
s32 FSCore::Seek(u64 fd, u32 offset, FS::SeekMode mode, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand Down Expand Up @@ -422,23 +433,20 @@ struct ISFSFileStats
#pragma pack(pop)

template <typename T>
static Result<T> GetParams(const IOCtlRequest& request)
static Result<T> GetParams(Memory::MemoryManager& memory, const IOCtlRequest& request)
{
if (request.buffer_in_size < sizeof(T))
return ResultCode::Invalid;

auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();

T params;
memory.CopyFromEmu(&params, request.buffer_in, sizeof(params));
return params;
}

std::optional<IPCReply> FSDevice::IOCtl(const IOCtlRequest& request)
{
const auto it = m_fd_map.find(request.fd);
if (it == m_fd_map.end())
const auto it = m_core.m_fd_map.find(request.fd);
if (it == m_core.m_fd_map.end())
return IPCReply(ConvertResult(ResultCode::Invalid));

switch (request.request)
Expand Down Expand Up @@ -472,8 +480,8 @@ std::optional<IPCReply> FSDevice::IOCtl(const IOCtlRequest& request)

std::optional<IPCReply> FSDevice::IOCtlV(const IOCtlVRequest& request)
{
const auto it = m_fd_map.find(request.fd);
if (it == m_fd_map.end())
const auto it = m_core.m_fd_map.find(request.fd);
if (it == m_core.m_fd_map.end())
return IPCReply(ConvertResult(ResultCode::Invalid));

switch (request.request)
Expand Down Expand Up @@ -506,7 +514,7 @@ IPCReply FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)
if (!stats)
return IPCReply(ConvertResult(stats.Error()));

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

ISFSNandStats out;
Expand All @@ -523,7 +531,7 @@ IPCReply FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)

IPCReply FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));

Expand All @@ -541,7 +549,7 @@ IPCReply FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& requ
return GetFSReply(ConvertResult(ResultCode::Invalid));
}

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

u32 file_list_address, file_count_address, max_count;
Expand Down Expand Up @@ -592,7 +600,7 @@ IPCReply FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& requ

IPCReply FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));

Expand All @@ -607,7 +615,7 @@ IPCReply FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& reques
if (request.buffer_in_size < 64 || request.buffer_out_size < sizeof(ISFSParams))
return GetFSReply(ConvertResult(ResultCode::Invalid));

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const std::string path = memory.GetString(request.buffer_in, 64);
Expand All @@ -629,7 +637,7 @@ IPCReply FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& reques
return GetFSReply(IPC_SUCCESS, ticks);
}

FS::ResultCode FSDevice::DeleteFile(FS::Uid uid, FS::Gid gid, const std::string& path, Ticks ticks)
FS::ResultCode FSCore::DeleteFile(FS::Uid uid, FS::Gid gid, const std::string& path, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand All @@ -644,16 +652,17 @@ IPCReply FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest& request)
if (request.buffer_in_size < 64)
return GetFSReply(ConvertResult(ResultCode::Invalid));

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const std::string path = memory.GetString(request.buffer_in, 64);
return MakeIPCReply(
[&](Ticks ticks) { return ConvertResult(DeleteFile(handle.uid, handle.gid, path, ticks)); });
return MakeIPCReply([&](Ticks ticks) {
return ConvertResult(m_core.DeleteFile(handle.uid, handle.gid, path, ticks));
});
}

FS::ResultCode FSDevice::RenameFile(FS::Uid uid, FS::Gid gid, const std::string& old_path,
const std::string& new_path, Ticks ticks)
FS::ResultCode FSCore::RenameFile(FS::Uid uid, FS::Gid gid, const std::string& old_path,
const std::string& new_path, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand All @@ -668,18 +677,18 @@ IPCReply FSDevice::RenameFile(const Handle& handle, const IOCtlRequest& request)
if (request.buffer_in_size < 64 * 2)
return GetFSReply(ConvertResult(ResultCode::Invalid));

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const std::string old_path = memory.GetString(request.buffer_in, 64);
const std::string new_path = memory.GetString(request.buffer_in + 64, 64);
return MakeIPCReply([&](Ticks ticks) {
return ConvertResult(RenameFile(handle.uid, handle.gid, old_path, new_path, ticks));
return ConvertResult(m_core.RenameFile(handle.uid, handle.gid, old_path, new_path, ticks));
});
}

FS::ResultCode FSDevice::CreateFile(FS::Uid uid, FS::Gid gid, const std::string& path,
FS::FileAttribute attribute, FS::Modes modes, Ticks ticks)
FS::ResultCode FSCore::CreateFile(FS::Uid uid, FS::Gid gid, const std::string& path,
FS::FileAttribute attribute, FS::Modes modes, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);

Expand All @@ -691,18 +700,18 @@ FS::ResultCode FSDevice::CreateFile(FS::Uid uid, FS::Gid gid, const std::string&

IPCReply FSDevice::CreateFile(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));
return MakeIPCReply([&](Ticks ticks) {
return ConvertResult(
CreateFile(handle.uid, handle.gid, params->path, params->attribute, params->modes));
m_core.CreateFile(handle.uid, handle.gid, params->path, params->attribute, params->modes));
});
}

IPCReply FSDevice::SetFileVersionControl(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
const auto params = GetParams<ISFSParams>(GetSystem().GetMemory(), request);
if (!params)
return GetFSReply(ConvertResult(params.Error()));

Expand All @@ -718,11 +727,11 @@ IPCReply FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& reques
return GetFSReply(ConvertResult(ResultCode::Invalid));

return MakeIPCReply([&](Ticks ticks) {
const Result<FileStatus> status = GetFileStatus(request.fd, ticks);
const Result<FileStatus> status = m_core.GetFileStatus(request.fd, ticks);
if (!status)
return ConvertResult(status.Error());

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

ISFSFileStats out;
Expand All @@ -733,7 +742,7 @@ IPCReply FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& reques
});
}

FS::Result<FS::FileStatus> FSDevice::GetFileStatus(u64 fd, Ticks ticks)
FS::Result<FS::FileStatus> FSCore::GetFileStatus(u64 fd, Ticks ticks)
{
ticks.Add(IPC_OVERHEAD_TICKS);
const auto& handle = m_fd_map[fd];
Expand All @@ -753,7 +762,7 @@ IPCReply FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& request)
return GetFSReply(ConvertResult(ResultCode::Invalid));
}

auto& system = Core::System::GetInstance();
auto& system = GetSystem();
auto& memory = system.GetMemory();

const std::string directory = memory.GetString(request.in_vectors[0].address, 64);
Expand Down
75 changes: 49 additions & 26 deletions Source/Core/Core/IOS/FS/FileSystemProxy.h
Expand Up @@ -20,13 +20,22 @@ namespace IOS::HLE
{
constexpr FS::Fd INVALID_FD = 0xffffffff;

class FSDevice : public Device
class FSDevice;

class FSCore final
{
public:
explicit FSCore(Kernel& ios);
FSCore(const FSCore& other) = delete;
FSCore(FSCore&& other) = delete;
FSCore& operator=(const FSCore& other) = delete;
FSCore& operator=(FSCore&& other) = delete;
~FSCore();

class ScopedFd
{
public:
ScopedFd(FSDevice* fs, s64 fd, Ticks tick_tracker = {})
ScopedFd(FSCore* fs, s64 fd, Ticks tick_tracker = {})
: m_fs{fs}, m_fd{fd}, m_tick_tracker{tick_tracker}
{
}
Expand All @@ -46,13 +55,11 @@ class FSDevice : public Device
s64 Release() { return std::exchange(m_fd, -1); }

private:
FSDevice* m_fs{};
FSCore* m_fs{};
s64 m_fd = -1;
Ticks m_tick_tracker{};
};

FSDevice(Kernel& ios, const std::string& device_name);

// These are the equivalent of the IPC command handlers so IPC overhead is included
// in timing calculations.
ScopedFd Open(FS::Uid uid, FS::Gid gid, const std::string& path, FS::Mode mode,
Expand All @@ -78,16 +85,6 @@ class FSDevice : public Device

std::shared_ptr<FS::FileSystem> GetFS() const { return m_ios.GetFS(); }

void DoState(PointerWrap& p) override;

std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> Read(const ReadWriteRequest& request) override;
std::optional<IPCReply> Write(const ReadWriteRequest& request) override;
std::optional<IPCReply> Seek(const SeekRequest& request) override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;

private:
struct Handle
{
Expand All @@ -99,6 +96,40 @@ class FSDevice : public Device
bool superblock_flush_needed = false;
};

u64 EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command, u32 size);
u64 SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size);
u64 SimulateFlushFileCache();
bool HasCacheForFile(u64 fd, u32 offset) const;

Kernel& m_ios;

bool m_dirty_cache = false;
u16 m_cache_chain_index = 0;
std::optional<u64> m_cache_fd;
// The first 0x18 IDs are reserved for the PPC.
u64 m_next_fd = 0x18;
std::map<u64, Handle> m_fd_map;

friend class FSDevice;
};

class FSDevice final : public EmulationDevice
{
public:
FSDevice(EmulationKernel& ios, FSCore& core, const std::string& device_name);
~FSDevice();

void DoState(PointerWrap& p) override;

std::optional<IPCReply> Open(const OpenRequest& request) override;
std::optional<IPCReply> Close(u32 fd) override;
std::optional<IPCReply> Read(const ReadWriteRequest& request) override;
std::optional<IPCReply> Write(const ReadWriteRequest& request) override;
std::optional<IPCReply> Seek(const SeekRequest& request) override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;

private:
enum
{
ISFS_IOCTL_FORMAT = 1,
Expand All @@ -116,6 +147,8 @@ class FSDevice : public Device
ISFS_IOCTL_SHUTDOWN = 13,
};

using Handle = FSCore::Handle;

IPCReply Format(const Handle& handle, const IOCtlRequest& request);
IPCReply GetStats(const Handle& handle, const IOCtlRequest& request);
IPCReply CreateDirectory(const Handle& handle, const IOCtlRequest& request);
Expand All @@ -130,16 +163,6 @@ class FSDevice : public Device
IPCReply GetUsage(const Handle& handle, const IOCtlVRequest& request);
IPCReply Shutdown(const Handle& handle, const IOCtlRequest& request);

u64 EstimateTicksForReadWrite(const Handle& handle, u64 fd, IPCCommandType command, u32 size);
u64 SimulatePopulateFileCache(u64 fd, u32 offset, u32 file_size);
u64 SimulateFlushFileCache();
bool HasCacheForFile(u64 fd, u32 offset) const;

bool m_dirty_cache = false;
u16 m_cache_chain_index = 0;
std::optional<u64> m_cache_fd;
// The first 0x18 IDs are reserved for the PPC.
u64 m_next_fd = 0x18;
std::map<u64, Handle> m_fd_map;
FSCore& m_core;
};
} // namespace IOS::HLE
89 changes: 44 additions & 45 deletions Source/Core/Core/IOS/IOS.cpp
Expand Up @@ -8,7 +8,6 @@
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <utility>

Expand Down Expand Up @@ -300,17 +299,15 @@ Kernel::Kernel(IOSC::ConsoleType console_type) : m_iosc(console_type)
if (m_is_responsible_for_nand_root)
Core::InitializeWiiRoot(false);

AddCoreDevices();
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);

m_fs_core = std::make_unique<FSCore>(*this);
m_es_core = std::make_unique<ESCore>(*this);
}

Kernel::~Kernel()
{
{
std::lock_guard lock(m_device_map_mutex);
m_device_map.clear();
m_socket_manager.reset();
}

if (m_is_responsible_for_nand_root)
Core::ShutdownWiiRoot();
}
Expand All @@ -333,13 +330,23 @@ EmulationKernel::EmulationKernel(Core::System& system, u64 title_id)
return;
}

AddCoreDevices();
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);

m_fs_core = std::make_unique<FSCore>(*this);
AddDevice(std::make_unique<FSDevice>(*this, *m_fs_core, "/dev/fs"));
m_es_core = std::make_unique<ESCore>(*this);
AddDevice(std::make_unique<ESDevice>(*this, *m_es_core, "/dev/es"));

AddStaticDevices();
}

EmulationKernel::~EmulationKernel()
{
Core::System::GetInstance().GetCoreTiming().RemoveAllEvents(s_event_enqueue);

m_device_map.clear();
m_socket_manager.reset();
}

// The title ID is a u64 where the first 32 bits are used for the title type.
Expand All @@ -355,12 +362,22 @@ std::shared_ptr<FS::FileSystem> Kernel::GetFS()
return m_fs;
}

std::shared_ptr<FSDevice> Kernel::GetFSDevice()
FSCore& Kernel::GetFSCore()
{
return *m_fs_core;
}

std::shared_ptr<FSDevice> EmulationKernel::GetFSDevice()
{
return std::static_pointer_cast<FSDevice>(m_device_map.at("/dev/fs"));
}

std::shared_ptr<ESDevice> Kernel::GetES()
ESCore& Kernel::GetESCore()
{
return *m_es_core;
}

std::shared_ptr<ESDevice> EmulationKernel::GetESDevice()
{
return std::static_pointer_cast<ESDevice>(m_device_map.at("/dev/es"));
}
Expand All @@ -372,51 +389,51 @@ std::shared_ptr<WiiSockMan> EmulationKernel::GetSocketManager()

// Since we don't have actual processes, we keep track of only the PPC's UID/GID.
// These functions roughly correspond to syscalls 0x2b, 0x2c, 0x2d, 0x2e (though only for the PPC).
void Kernel::SetUidForPPC(u32 uid)
void EmulationKernel::SetUidForPPC(u32 uid)
{
m_ppc_uid = uid;
}

u32 Kernel::GetUidForPPC() const
u32 EmulationKernel::GetUidForPPC() const
{
return m_ppc_uid;
}

void Kernel::SetGidForPPC(u16 gid)
void EmulationKernel::SetGidForPPC(u16 gid)
{
m_ppc_gid = gid;
}

u16 Kernel::GetGidForPPC() const
u16 EmulationKernel::GetGidForPPC() const
{
return m_ppc_gid;
}

static std::vector<u8> ReadBootContent(FSDevice* fs, const std::string& path, size_t max_size,
static std::vector<u8> ReadBootContent(FSCore& fs, const std::string& path, size_t max_size,
Ticks ticks = {})
{
const auto fd = fs->Open(0, 0, path, FS::Mode::Read, {}, ticks);
const auto fd = fs.Open(0, 0, path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
return {};

const size_t file_size = fs->GetFileStatus(fd.Get(), ticks)->size;
const size_t file_size = fs.GetFileStatus(fd.Get(), ticks)->size;
if (max_size != 0 && file_size > max_size)
return {};

std::vector<u8> buffer(file_size);
if (!fs->Read(fd.Get(), buffer.data(), buffer.size(), ticks))
if (!fs.Read(fd.Get(), buffer.data(), buffer.size(), ticks))
return {};
return buffer;
}

// This corresponds to syscall 0x41, which loads a binary from the NAND and bootstraps the PPC.
// Unlike 0x42, IOS will set up some constants in memory before booting the PPC.
bool Kernel::BootstrapPPC(Core::System& system, const std::string& boot_content_path)
bool EmulationKernel::BootstrapPPC(Core::System& system, const std::string& boot_content_path)
{
// Seeking and processing overhead is ignored as most time is spent reading from the NAND.
u64 ticks = 0;

const DolReader dol{ReadBootContent(GetFSDevice().get(), boot_content_path, 0, &ticks)};
const DolReader dol{ReadBootContent(GetFSCore(), boot_content_path, 0, &ticks)};

if (!dol.IsValid())
return false;
Expand Down Expand Up @@ -485,8 +502,8 @@ static constexpr SystemTimers::TimeBaseTick GetIOSBootTicks(u32 version)
// Passing a boot content path is optional because we do not require IOSes
// to be installed at the moment. If one is passed, the boot binary must exist
// on the NAND, or the call will fail like on a Wii.
bool Kernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_ppc,
const std::string& boot_content_path)
bool EmulationKernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_ppc,
const std::string& boot_content_path)
{
// IOS suspends regular PPC<->ARM IPC before loading a new IOS.
// IPC is not resumed if the boot fails for any reason.
Expand All @@ -497,7 +514,7 @@ bool Kernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_
// Load the ARM binary to memory (if possible).
// Because we do not actually emulate the Starlet, only load the sections that are in MEM1.

ARMBinary binary{ReadBootContent(GetFSDevice().get(), boot_content_path, 0xB00000)};
ARMBinary binary{ReadBootContent(GetFSCore(), boot_content_path, 0xB00000)};
if (!binary.IsValid())
return false;

Expand All @@ -522,7 +539,7 @@ bool Kernel::BootIOS(Core::System& system, const u64 ios_title_id, HangPPC hang_
return true;
}

void Kernel::InitIPC()
void EmulationKernel::InitIPC()
{
if (!Core::IsRunning())
return;
Expand All @@ -531,26 +548,14 @@ void Kernel::InitIPC()
GenerateAck(0);
}

void Kernel::AddDevice(std::unique_ptr<Device> device)
void EmulationKernel::AddDevice(std::unique_ptr<Device> device)
{
ASSERT(device->GetDeviceType() == Device::DeviceType::Static);
m_device_map.insert_or_assign(device->GetDeviceName(), std::move(device));
}

void Kernel::AddCoreDevices()
{
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
ASSERT(m_fs);

std::lock_guard lock(m_device_map_mutex);
AddDevice(std::make_unique<FSDevice>(*this, "/dev/fs"));
AddDevice(std::make_unique<ESDevice>(*this, "/dev/es"));
}

void EmulationKernel::AddStaticDevices()
{
std::lock_guard lock(m_device_map_mutex);

const Feature features = GetFeatures(GetVersion());

// Dolphin-specific device for letting homebrew access and alter emulator state.
Expand Down Expand Up @@ -637,18 +642,12 @@ s32 EmulationKernel::GetFreeDeviceID()
return -1;
}

std::shared_ptr<Device> Kernel::GetDeviceByName(std::string_view device_name)
std::shared_ptr<Device> EmulationKernel::GetDeviceByName(std::string_view device_name)
{
std::lock_guard lock(m_device_map_mutex);
const auto iterator = m_device_map.find(device_name);
return iterator != m_device_map.end() ? iterator->second : nullptr;
}

std::shared_ptr<Device> EmulationKernel::GetDeviceByName(std::string_view device_name)
{
return Kernel::GetDeviceByName(device_name);
}

// Returns the FD for the newly opened device (on success) or an error code.
std::optional<IPCReply> EmulationKernel::OpenDevice(OpenRequest& request)
{
Expand Down
68 changes: 37 additions & 31 deletions Source/Core/Core/IOS/IOS.h
Expand Up @@ -7,7 +7,6 @@
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
Expand All @@ -33,7 +32,9 @@ class FileSystem;
}

class Device;
class ESCore;
class ESDevice;
class FSCore;
class FSDevice;
class WiiSockMan;

Expand Down Expand Up @@ -122,45 +123,21 @@ class Kernel
// These are *always* part of the IOS kernel and always available.
// They are also the only available resource managers even before loading any module.
std::shared_ptr<FS::FileSystem> GetFS();
std::shared_ptr<FSDevice> GetFSDevice();
std::shared_ptr<ESDevice> GetES();

void SetUidForPPC(u32 uid);
u32 GetUidForPPC() const;
void SetGidForPPC(u16 gid);
u16 GetGidForPPC() const;
FSCore& GetFSCore();
ESCore& GetESCore();

bool BootstrapPPC(Core::System& system, const std::string& boot_content_path);
bool BootIOS(Core::System& system, u64 ios_title_id, HangPPC hang_ppc = HangPPC::No,
const std::string& boot_content_path = {});
void InitIPC();
u32 GetVersion() const;

IOSC& GetIOSC();

protected:
explicit Kernel(u64 title_id);

void AddDevice(std::unique_ptr<Device> device);
void AddCoreDevices();
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);
std::unique_ptr<FSCore> m_fs_core;
std::unique_ptr<ESCore> m_es_core;

bool m_is_responsible_for_nand_root = false;
u64 m_title_id = 0;
static constexpr u8 IPC_MAX_FDS = 0x18;
std::map<std::string, std::shared_ptr<Device>, std::less<>> m_device_map;
std::mutex m_device_map_mutex;
// TODO: make this fdmap per process.
std::array<std::shared_ptr<Device>, IPC_MAX_FDS> m_fdmap;

u32 m_ppc_uid = 0;
u16 m_ppc_gid = 0;

using IPCMsgQueue = std::deque<u32>;
IPCMsgQueue m_request_queue; // ppc -> arm
IPCMsgQueue m_reply_queue; // arm -> ppc
u64 m_last_reply_time = 0;
bool m_ipc_paused = false;

IOSC m_iosc;
std::shared_ptr<FS::FileSystem> m_fs;
Expand All @@ -178,6 +155,9 @@ class EmulationKernel final : public Kernel
// This only works for devices which are part of the device map.
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);

std::shared_ptr<FSDevice> GetFSDevice();
std::shared_ptr<ESDevice> GetESDevice();

void DoState(PointerWrap& p);
void UpdateDevices();
void UpdateWantDeterminism(bool new_want_determinism);
Expand All @@ -191,17 +171,43 @@ class EmulationKernel final : public Kernel
void EnqueueIPCReply(const Request& request, s32 return_value, s64 cycles_in_future = 0,
CoreTiming::FromThread from = CoreTiming::FromThread::CPU);

void SetUidForPPC(u32 uid);
u32 GetUidForPPC() const;
void SetGidForPPC(u16 gid);
u16 GetGidForPPC() const;

bool BootstrapPPC(Core::System& system, const std::string& boot_content_path);
bool BootIOS(Core::System& system, u64 ios_title_id, HangPPC hang_ppc = HangPPC::No,
const std::string& boot_content_path = {});
void InitIPC();

Core::System& GetSystem() const { return m_system; }

private:
Core::System& m_system;

void ExecuteIPCCommand(u32 address);
std::optional<IPCReply> HandleIPCCommand(const Request& request);

void AddDevice(std::unique_ptr<Device> device);

void AddStaticDevices();
s32 GetFreeDeviceID();
std::optional<IPCReply> OpenDevice(OpenRequest& request);

Core::System& m_system;

static constexpr u8 IPC_MAX_FDS = 0x18;
std::map<std::string, std::shared_ptr<Device>, std::less<>> m_device_map;
// TODO: make this fdmap per process.
std::array<std::shared_ptr<Device>, IPC_MAX_FDS> m_fdmap;

u32 m_ppc_uid = 0;
u16 m_ppc_gid = 0;

using IPCMsgQueue = std::deque<u32>;
IPCMsgQueue m_request_queue; // ppc -> arm
IPCMsgQueue m_reply_queue; // arm -> ppc
u64 m_last_reply_time = 0;
bool m_ipc_paused = false;
};

// Used for controlling and accessing an IOS instance that is tied to emulation.
Expand Down
7 changes: 4 additions & 3 deletions Source/Core/Core/IOS/WFS/WFSI.cpp
Expand Up @@ -165,7 +165,8 @@ std::optional<IPCReply> WFSIDevice::IOCtl(const IOCtlRequest& request)
memory.CopyFromEmu(tmd_bytes.data(), tmd_addr, tmd_size);
m_tmd.SetBytes(std::move(tmd_bytes));

const ES::TicketReader ticket = m_ios.GetES()->FindSignedTicket(m_tmd.GetTitleId());
const ES::TicketReader ticket =
GetEmulationKernel().GetESCore().FindSignedTicket(m_tmd.GetTitleId());
if (!ticket.IsValid())
{
return_error_code = -11028;
Expand Down Expand Up @@ -385,14 +386,14 @@ std::optional<IPCReply> WFSIDevice::IOCtl(const IOCtlRequest& request)
{
INFO_LOG_FMT(IOS_WFS, "IOCTL_WFSI_INIT");
u64 tid;
if (GetEmulationKernel().GetES()->GetTitleId(&tid) < 0)
if (GetEmulationKernel().GetESCore().GetTitleId(&tid) < 0)
{
ERROR_LOG_FMT(IOS_WFS, "IOCTL_WFSI_INIT: Could not get title id.");
return_error_code = IPC_EINVAL;
break;
}

const ES::TMDReader tmd = GetEmulationKernel().GetES()->FindInstalledTMD(tid);
const ES::TMDReader tmd = GetEmulationKernel().GetESCore().FindInstalledTMD(tid);
SetCurrentTitleIdAndGroupId(tmd.GetTitleId(), tmd.GetGroupId());
break;
}
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/NetPlayServer.cpp
Expand Up @@ -1720,7 +1720,7 @@ std::optional<SaveSyncInfo> NetPlayServer::CollectSaveSyncInfo()
if (m_settings.savedata_sync_all_wii)
{
IOS::HLE::Kernel ios;
for (const u64 title : ios.GetES()->GetInstalledTitles())
for (const u64 title : ios.GetESCore().GetInstalledTitles())
{
auto save = WiiSave::MakeNandStorage(sync_info.configured_fs.get(), title);
if (save && save->ReadHeader().has_value() && save->ReadBkHeader().has_value() &&
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/WiiRoot.cpp
Expand Up @@ -416,7 +416,7 @@ void CleanUpWiiFileSystemContents(const BootSessionData& boot_session_data)
// cleanup process.
const bool copy_all = !netplay_settings || netplay_settings->savedata_sync_all_wii;
for (const u64 title_id :
(copy_all ? ios->GetES()->GetInstalledTitles() : boot_session_data.GetWiiSyncTitles()))
(copy_all ? ios->GetESCore().GetInstalledTitles() : boot_session_data.GetWiiSyncTitles()))
{
INFO_LOG_FMT(CORE, "Wii FS Cleanup: Copying {0:016x}.", title_id);

Expand Down
93 changes: 47 additions & 46 deletions Source/Core/Core/WiiUtils.cpp
Expand Up @@ -49,7 +49,7 @@
namespace WiiUtils
{
static bool ImportWAD(IOS::HLE::Kernel& ios, const DiscIO::VolumeWAD& wad,
IOS::HLE::ESDevice::VerifySignature verify_signature)
IOS::HLE::ESCore::VerifySignature verify_signature)
{
if (!wad.GetTicket().IsValid() || !wad.GetTMD().IsValid())
{
Expand All @@ -58,20 +58,20 @@ static bool ImportWAD(IOS::HLE::Kernel& ios, const DiscIO::VolumeWAD& wad,
}

const auto tmd = wad.GetTMD();
const auto es = ios.GetES();
auto& es = ios.GetESCore();
const auto fs = ios.GetFS();

IOS::HLE::ESDevice::Context context;
IOS::HLE::ESCore::Context context;
IOS::HLE::ReturnCode ret;

// Ensure the common key index is correct, as it's checked by IOS.
IOS::ES::TicketReader ticket = wad.GetTicketWithFixedCommonKey();

while ((ret = es->ImportTicket(ticket.GetBytes(), wad.GetCertificateChain(),
IOS::HLE::ESDevice::TicketImportType::Unpersonalised,
verify_signature)) < 0 ||
(ret = es->ImportTitleInit(context, tmd.GetBytes(), wad.GetCertificateChain(),
verify_signature)) < 0)
while ((ret = es.ImportTicket(ticket.GetBytes(), wad.GetCertificateChain(),
IOS::HLE::ESCore::TicketImportType::Unpersonalised,
verify_signature)) < 0 ||
(ret = es.ImportTitleInit(context, tmd.GetBytes(), wad.GetCertificateChain(),
verify_signature)) < 0)
{
if (ret != IOS::HLE::IOSC_FAIL_CHECKVALUE)
{
Expand All @@ -87,9 +87,9 @@ static bool ImportWAD(IOS::HLE::Kernel& ios, const DiscIO::VolumeWAD& wad,
{
const std::vector<u8> data = wad.GetContent(content.index);

if (es->ImportContentBegin(context, title_id, content.id) < 0 ||
es->ImportContentData(context, 0, data.data(), static_cast<u32>(data.size())) < 0 ||
es->ImportContentEnd(context, 0) < 0)
if (es.ImportContentBegin(context, title_id, content.id) < 0 ||
es.ImportContentData(context, 0, data.data(), static_cast<u32>(data.size())) < 0 ||
es.ImportContentEnd(context, 0) < 0)
{
PanicAlertFmtT("WAD installation failed: Could not import content {0:08x}.", content.id);
return false;
Expand All @@ -98,8 +98,8 @@ static bool ImportWAD(IOS::HLE::Kernel& ios, const DiscIO::VolumeWAD& wad,
return true;
}();

if ((contents_imported && es->ImportTitleDone(context) < 0) ||
(!contents_imported && es->ImportTitleCancel(context) < 0))
if ((contents_imported && es.ImportTitleDone(context) < 0) ||
(!contents_imported && es.ImportTitleCancel(context) < 0))
{
PanicAlertFmtT("WAD installation failed: Could not finalise title import.");
return false;
Expand Down Expand Up @@ -151,8 +151,8 @@ bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::VolumeWAD& wad, InstallType
const u64 title_id = wad.GetTMD().GetTitleId();

// Skip the install if the WAD is already installed.
const auto installed_contents = ios.GetES()->GetStoredContentsFromTMD(
wad.GetTMD(), IOS::HLE::ESDevice::CheckContentHashes::Yes);
const auto installed_contents = ios.GetESCore().GetStoredContentsFromTMD(
wad.GetTMD(), IOS::HLE::ESCore::CheckContentHashes::Yes);
if (wad.GetTMD().GetContents() == installed_contents)
{
// Clear the "temporary title ID" flag in case the user tries to permanently install a title
Expand All @@ -164,7 +164,7 @@ bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::VolumeWAD& wad, InstallType

// If a different version is currently installed, warn the user to make sure
// they don't overwrite the current version by mistake.
const IOS::ES::TMDReader installed_tmd = ios.GetES()->FindInstalledTMD(title_id);
const IOS::ES::TMDReader installed_tmd = ios.GetESCore().FindInstalledTMD(title_id);
const bool has_another_version =
installed_tmd.IsValid() && installed_tmd.GetTitleVersion() != wad.GetTMD().GetTitleVersion();
if (has_another_version &&
Expand All @@ -178,10 +178,10 @@ bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::VolumeWAD& wad, InstallType

// Delete a previous temporary title, if it exists.
if (previous_temporary_title_id)
ios.GetES()->DeleteTitleContent(previous_temporary_title_id);
ios.GetESCore().DeleteTitleContent(previous_temporary_title_id);

// A lot of people use fakesigned WADs, so disable signature checking when installing a WAD.
if (!ImportWAD(ios, wad, IOS::HLE::ESDevice::VerifySignature::No))
if (!ImportWAD(ios, wad, IOS::HLE::ESCore::VerifySignature::No))
return false;

// Keep track of the title ID so this title can be removed to make room for any future install.
Expand All @@ -207,7 +207,7 @@ bool InstallWAD(const std::string& wad_path)
bool UninstallTitle(u64 title_id)
{
IOS::HLE::Kernel ios;
return ios.GetES()->DeleteTitleContent(title_id) == IOS::HLE::IPC_SUCCESS;
return ios.GetESCore().DeleteTitleContent(title_id) == IOS::HLE::IPC_SUCCESS;
}

bool IsTitleInstalled(u64 title_id)
Expand Down Expand Up @@ -266,7 +266,7 @@ IOS::ES::TMDReader FindBackupTMD(IOS::HLE::FS::FileSystem& fs, u64 title_id)
}
}

bool EnsureTMDIsImported(IOS::HLE::FS::FileSystem& fs, IOS::HLE::ESDevice& es, u64 title_id)
bool EnsureTMDIsImported(IOS::HLE::FS::FileSystem& fs, IOS::HLE::ESCore& es, u64 title_id)
{
if (IsTMDImported(fs, title_id))
return true;
Expand All @@ -275,7 +275,7 @@ bool EnsureTMDIsImported(IOS::HLE::FS::FileSystem& fs, IOS::HLE::ESDevice& es, u
if (!tmd.IsValid())
return false;

IOS::HLE::ESDevice::Context context;
IOS::HLE::ESCore::Context context;
context.uid = IOS::SYSMENU_UID;
context.gid = IOS::SYSMENU_GID;
const auto import_result =
Expand Down Expand Up @@ -308,7 +308,7 @@ class SystemUpdater
std::string SystemUpdater::GetDeviceRegion()
{
// Try to determine the region from an installed system menu.
const auto tmd = m_ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
const auto tmd = m_ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU);
if (tmd.IsValid())
{
const DiscIO::Region region = tmd.GetRegion();
Expand All @@ -325,7 +325,7 @@ std::string SystemUpdater::GetDeviceRegion()
std::string SystemUpdater::GetDeviceId()
{
u32 ios_device_id;
if (m_ios.GetES()->GetDeviceId(&ios_device_id) < 0)
if (m_ios.GetESCore().GetDeviceId(&ios_device_id) < 0)
return "";
return std::to_string((u64(1) << 32) | ios_device_id);
}
Expand Down Expand Up @@ -417,10 +417,10 @@ OnlineSystemUpdater::ParseTitlesResponse(const std::vector<u8>& response) const

bool OnlineSystemUpdater::ShouldInstallTitle(const TitleInfo& title)
{
const auto es = m_ios.GetES();
const auto installed_tmd = es->FindInstalledTMD(title.id);
const auto& es = m_ios.GetESCore();
const auto installed_tmd = es.FindInstalledTMD(title.id);
return !(installed_tmd.IsValid() && installed_tmd.GetTitleVersion() >= title.version &&
es->GetStoredContentsFromTMD(installed_tmd).size() == installed_tmd.GetNumContents());
es.GetStoredContentsFromTMD(installed_tmd).size() == installed_tmd.GetNumContents());
}

constexpr const char* GET_SYSTEM_TITLES_REQUEST_PAYLOAD = R"(<?xml version="1.0" encoding="UTF-8"?>
Expand Down Expand Up @@ -545,8 +545,8 @@ UpdateResult OnlineSystemUpdater::InstallTitleFromNUS(const std::string& prefix_

// Import the ticket.
IOS::HLE::ReturnCode ret = IOS::HLE::IPC_SUCCESS;
const auto es = m_ios.GetES();
if ((ret = es->ImportTicket(ticket.first, ticket.second)) < 0)
auto& es = m_ios.GetESCore();
if ((ret = es.ImportTicket(ticket.first, ticket.second)) < 0)
{
ERROR_LOG_FMT(CORE, "Failed to import ticket: error {}", static_cast<u32>(ret));
return UpdateResult::ImportFailed;
Expand All @@ -564,7 +564,7 @@ UpdateResult OnlineSystemUpdater::InstallTitleFromNUS(const std::string& prefix_
const u64 ios_id = tmd.first.GetIOSId();
if (ios_id != 0 && IOS::ES::IsTitleType(ios_id, IOS::ES::TitleType::System))
{
if (!es->FindInstalledTMD(ios_id).IsValid())
if (!es.FindInstalledTMD(ios_id).IsValid())
{
WARN_LOG_FMT(CORE, "Importing required system title {:016x} first", ios_id);
const UpdateResult res = InstallTitleFromNUS(prefix_url, {ios_id, 0}, updated_titles);
Expand All @@ -577,15 +577,15 @@ UpdateResult OnlineSystemUpdater::InstallTitleFromNUS(const std::string& prefix_
}

// Initialise the title import.
IOS::HLE::ESDevice::Context context;
if ((ret = es->ImportTitleInit(context, tmd.first.GetBytes(), tmd.second)) < 0)
IOS::HLE::ESCore::Context context;
if ((ret = es.ImportTitleInit(context, tmd.first.GetBytes(), tmd.second)) < 0)
{
ERROR_LOG_FMT(CORE, "Failed to initialise title import: error {}", static_cast<u32>(ret));
return UpdateResult::ImportFailed;
}

// Now download and install contents listed in the TMD.
const std::vector<IOS::ES::Content> stored_contents = es->GetStoredContentsFromTMD(tmd.first);
const std::vector<IOS::ES::Content> stored_contents = es.GetStoredContentsFromTMD(tmd.first);
const UpdateResult import_result = [&]() {
for (const IOS::ES::Content& content : tmd.first.GetContents())
{
Expand All @@ -598,7 +598,7 @@ UpdateResult OnlineSystemUpdater::InstallTitleFromNUS(const std::string& prefix_
if (is_already_installed)
continue;

if ((ret = es->ImportContentBegin(context, title.id, content.id)) < 0)
if ((ret = es.ImportContentBegin(context, title.id, content.id)) < 0)
{
ERROR_LOG_FMT(CORE, "Failed to initialise import for content {:08x}: error {}", content.id,
static_cast<u32>(ret));
Expand All @@ -612,8 +612,8 @@ UpdateResult OnlineSystemUpdater::InstallTitleFromNUS(const std::string& prefix_
return UpdateResult::DownloadFailed;
}

if (es->ImportContentData(context, 0, data->data(), static_cast<u32>(data->size())) < 0 ||
es->ImportContentEnd(context, 0) < 0)
if (es.ImportContentData(context, 0, data->data(), static_cast<u32>(data->size())) < 0 ||
es.ImportContentEnd(context, 0) < 0)
{
ERROR_LOG_FMT(CORE, "Failed to import content {:08x}", content.id);
return UpdateResult::ImportFailed;
Expand All @@ -623,8 +623,8 @@ UpdateResult OnlineSystemUpdater::InstallTitleFromNUS(const std::string& prefix_
}();
const bool all_contents_imported = import_result == UpdateResult::Succeeded;

if ((all_contents_imported && (ret = es->ImportTitleDone(context)) < 0) ||
(!all_contents_imported && (ret = es->ImportTitleCancel(context)) < 0))
if ((all_contents_imported && (ret = es.ImportTitleDone(context)) < 0) ||
(!all_contents_imported && (ret = es.ImportTitleCancel(context)) < 0))
{
ERROR_LOG_FMT(CORE, "Failed to finalise title import: error {}", static_cast<u32>(ret));
return UpdateResult::ImportFailed;
Expand Down Expand Up @@ -742,7 +742,8 @@ UpdateResult DiscSystemUpdater::DoDiscUpdate()

// Do not allow mismatched regions, because installing an update will automatically change
// the Wii's region and may result in semi/full system menu bricks.
const IOS::ES::TMDReader system_menu_tmd = m_ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
const IOS::ES::TMDReader system_menu_tmd =
m_ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU);
if (system_menu_tmd.IsValid() && m_volume->GetRegion() != system_menu_tmd.GetRegion())
return UpdateResult::RegionMismatch;

Expand Down Expand Up @@ -826,8 +827,8 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs,
if (type != 2 && type != 3 && type != 6 && type != 7)
return UpdateResult::AlreadyUpToDate;

const IOS::ES::TMDReader tmd = m_ios.GetES()->FindInstalledTMD(title.id);
const IOS::ES::TicketReader ticket = m_ios.GetES()->FindSignedTicket(title.id);
const IOS::ES::TMDReader tmd = m_ios.GetESCore().FindInstalledTMD(title.id);
const IOS::ES::TicketReader ticket = m_ios.GetESCore().FindSignedTicket(title.id);

// Optional titles can be skipped if the ticket is present, even when the title isn't installed.
if (attrs.test(16) && ticket.IsValid())
Expand All @@ -846,7 +847,7 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs,
return UpdateResult::DiscReadFailed;
}
const DiscIO::VolumeWAD wad{std::move(blob)};
const bool success = ImportWAD(m_ios, wad, IOS::HLE::ESDevice::VerifySignature::Yes);
const bool success = ImportWAD(m_ios, wad, IOS::HLE::ESCore::VerifySignature::Yes);
return success ? UpdateResult::Succeeded : UpdateResult::ImportFailed;
}

Expand All @@ -865,7 +866,7 @@ UpdateResult DoDiscUpdate(UpdateCallback update_callback, const std::string& ima
static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair)
{
NANDCheckResult result;
const auto es = ios.GetES();
const auto& es = ios.GetESCore();

// Check for NANDs that were used with old Dolphin versions.
const std::string sys_replace_path =
Expand All @@ -892,7 +893,7 @@ static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair)
result.bad = true;
}

for (const u64 title_id : es->GetInstalledTitles())
for (const u64 title_id : es.GetInstalledTitles())
{
const std::string title_dir = Common::GetTitlePath(title_id, Common::FROM_CONFIGURED_ROOT);
const std::string content_dir = title_dir + "/content";
Expand All @@ -912,7 +913,7 @@ static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair)
}

// Check for incomplete title installs (missing ticket, TMD or contents).
const auto ticket = es->FindSignedTicket(title_id);
const auto ticket = es.FindSignedTicket(title_id);
if (!IOS::ES::IsDiscTitle(title_id) && !ticket.IsValid())
{
ERROR_LOG_FMT(CORE, "CheckNAND: Missing ticket for title {:016x}", title_id);
Expand All @@ -923,7 +924,7 @@ static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair)
result.bad = true;
}

const auto tmd = es->FindInstalledTMD(title_id);
const auto tmd = es.FindInstalledTMD(title_id);
if (!tmd.IsValid())
{
if (File::ScanDirectoryTree(content_dir, false).children.empty())
Expand All @@ -943,7 +944,7 @@ static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair)
continue;
}

const auto installed_contents = es->GetStoredContentsFromTMD(tmd);
const auto installed_contents = es.GetStoredContentsFromTMD(tmd);
const bool is_installed = std::any_of(installed_contents.begin(), installed_contents.end(),
[](const auto& content) { return !content.IsShared(); });

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/WiiUtils.h
Expand Up @@ -23,7 +23,7 @@ class VolumeWAD;
namespace IOS::HLE
{
class BluetoothEmuDevice;
class ESDevice;
class ESCore;
class Kernel;
} // namespace IOS::HLE

Expand Down Expand Up @@ -59,7 +59,7 @@ IOS::ES::TMDReader FindBackupTMD(IOS::HLE::FS::FileSystem& fs, u64 title_id);
// Checks if there's a title.tmd imported for the given title ID. If there is not, we attempt to
// re-import it from the TMDs stored in /title/00000001/00000002/data/tmds.sys.
// Returns true if, after this function call, we have an imported title.tmd, or false if not.
bool EnsureTMDIsImported(IOS::HLE::FS::FileSystem& fs, IOS::HLE::ESDevice& es, u64 title_id);
bool EnsureTMDIsImported(IOS::HLE::FS::FileSystem& fs, IOS::HLE::ESCore& es, u64 title_id);

enum class UpdateResult
{
Expand Down
26 changes: 13 additions & 13 deletions Source/Core/DiscIO/VolumeVerifier.cpp
Expand Up @@ -578,17 +578,17 @@ bool VolumeVerifier::CheckPartition(const Partition& partition)
const auto console_type =
IsDebugSigned() ? IOS::HLE::IOSC::ConsoleType::RVT : IOS::HLE::IOSC::ConsoleType::Retail;
IOS::HLE::Kernel ios(console_type);
const auto es = ios.GetES();
auto& es = ios.GetESCore();
const std::vector<u8>& cert_chain = m_volume.GetCertificateChain(partition);

if (IOS::HLE::IPC_SUCCESS !=
es->VerifyContainer(IOS::HLE::ESDevice::VerifyContainerType::Ticket,
IOS::HLE::ESDevice::VerifyMode::DoNotUpdateCertStore,
m_volume.GetTicket(partition), cert_chain) ||
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::Ticket,
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore,
m_volume.GetTicket(partition), cert_chain) ||
IOS::HLE::IPC_SUCCESS !=
es->VerifyContainer(IOS::HLE::ESDevice::VerifyContainerType::TMD,
IOS::HLE::ESDevice::VerifyMode::DoNotUpdateCertStore,
m_volume.GetTMD(partition), cert_chain))
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::TMD,
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore,
m_volume.GetTMD(partition), cert_chain))
{
AddProblem(Severity::Low,
Common::FmtFormatT("The {0} partition is not correctly signed.", name));
Expand Down Expand Up @@ -982,21 +982,21 @@ void VolumeVerifier::CheckMisc()
if (m_volume.GetVolumeType() == Platform::WiiWAD)
{
IOS::HLE::Kernel ios(m_ticket.GetConsoleType());
const auto es = ios.GetES();
auto& es = ios.GetESCore();
const std::vector<u8>& cert_chain = m_volume.GetCertificateChain(PARTITION_NONE);

if (IOS::HLE::IPC_SUCCESS !=
es->VerifyContainer(IOS::HLE::ESDevice::VerifyContainerType::Ticket,
IOS::HLE::ESDevice::VerifyMode::DoNotUpdateCertStore, m_ticket,
cert_chain))
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::Ticket,
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore, m_ticket,
cert_chain))
{
// i18n: "Ticket" here is a kind of digital authorization to use a certain title (e.g. a game)
AddProblem(Severity::Low, Common::GetStringT("The ticket is not correctly signed."));
}

if (IOS::HLE::IPC_SUCCESS !=
es->VerifyContainer(IOS::HLE::ESDevice::VerifyContainerType::TMD,
IOS::HLE::ESDevice::VerifyMode::DoNotUpdateCertStore, tmd, cert_chain))
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::TMD,
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore, tmd, cert_chain))
{
AddProblem(
Severity::Medium,
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DolphinQt/MenuBar.cpp
Expand Up @@ -1011,7 +1011,7 @@ void MenuBar::UpdateToolsMenu(bool emulation_started)
if (!emulation_started)
{
IOS::HLE::Kernel ios;
const auto tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
const auto tmd = ios.GetESCore().FindInstalledTMD(Titles::SYSTEM_MENU);

const QString sysmenu_version =
tmd.IsValid() ? QString::fromStdString(
Expand Down