@@ -13,6 +13,6 @@ class DolphinDevice final : public Device
public:
// Inherit the constructor from the Device class, since we don't need to do anything special.
using Device::Device;
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
};
} // namespace IOS::HLE
@@ -120,10 +120,10 @@ void TitleContext::Update(const ES::TMDReader& tmd_, const ES::TicketReader& tic
}
}

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

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);

@@ -132,7 +132,7 @@ IPCCommandResult ESDevice::GetTitleDirectory(const IOCtlVRequest& request)
static_cast<u32>(title_id));

INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETTITLEDIR: {}", path);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

ReturnCode ESDevice::GetTitleId(u64* title_id) const
@@ -143,20 +143,20 @@ ReturnCode ESDevice::GetTitleId(u64* title_id) const
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::GetTitleId(const IOCtlVRequest& request)
IPCReply ESDevice::GetTitleId(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u64 title_id;
const ReturnCode ret = GetTitleId(&title_id);
if (ret != IPC_SUCCESS)
return GetDefaultReply(ret);
return IPCReply(ret);

Memory::Write_U64(title_id, request.io_vectors[0].address);
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETTITLEID: {:08x}/{:08x}", static_cast<u32>(title_id >> 32),
static_cast<u32>(title_id));
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

static bool UpdateUIDAndGID(Kernel& kernel, const ES::TMDReader& tmd)
@@ -196,31 +196,31 @@ static ReturnCode CheckIsAllowedToSetUID(Kernel& kernel, const u32 caller_uid,
return ES_EINVAL;
}

IPCCommandResult ESDevice::SetUID(u32 uid, const IOCtlVRequest& request)
IPCReply ESDevice::SetUID(u32 uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);

const s32 ret = CheckIsAllowedToSetUID(m_ios, uid, m_title_context.tmd);
if (ret < 0)
{
ERROR_LOG_FMT(IOS_ES, "SetUID: Permission check failed with error {}", ret);
return GetDefaultReply(ret);
return IPCReply(ret);
}

const auto tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

if (!UpdateUIDAndGID(m_ios, tmd))
{
ERROR_LOG_FMT(IOS_ES, "SetUID: Failed to get UID for title {:016x}", title_id);
return GetDefaultReply(ES_SHORT_READ);
return IPCReply(ES_SHORT_READ);
}

return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

bool ESDevice::LaunchTitle(u64 title_id, bool skip_reload)
@@ -380,11 +380,11 @@ ESDevice::ContextArray::iterator ESDevice::FindInactiveContext()
[](const auto& context) { return !context.active; });
}

IPCCommandResult ESDevice::Open(const OpenRequest& request)
std::optional<IPCReply> ESDevice::Open(const OpenRequest& request)
{
auto context = FindInactiveContext();
if (context == m_contexts.end())
return GetDefaultReply(ES_FD_EXHAUSTED);
return IPCReply{ES_FD_EXHAUSTED};

context->active = true;
context->uid = request.uid;
@@ -393,26 +393,26 @@ IPCCommandResult ESDevice::Open(const OpenRequest& request)
return Device::Open(request);
}

IPCCommandResult ESDevice::Close(u32 fd)
std::optional<IPCReply> ESDevice::Close(u32 fd)
{
auto context = FindActiveContext(fd);
if (context == m_contexts.end())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

context->active = false;
context->ipc_fd = -1;

INFO_LOG_FMT(IOS_ES, "ES: Close");
m_is_active = false;
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::IOCtlV(const IOCtlVRequest& request)
std::optional<IPCReply> ESDevice::IOCtlV(const IOCtlVRequest& request)
{
DEBUG_LOG_FMT(IOS_ES, "{} ({:#x})", GetDeviceName(), request.request);
auto context = FindActiveContext(request.fd);
if (context == m_contexts.end())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

switch (request.request)
{
@@ -562,29 +562,29 @@ IPCCommandResult ESDevice::IOCtlV(const IOCtlVRequest& request)
PanicAlertFmt("IOS-ES: Unimplemented ioctlv {:#x} ({} in vectors, {} io vectors)",
request.request, request.in_vectors.size(), request.io_vectors.size());
request.DumpUnknown(GetDeviceName(), Common::Log::IOS_ES, Common::Log::LERROR);
return GetDefaultReply(IPC_EINVAL);
return IPCReply(IPC_EINVAL);

case IOCTL_ES_INVALID_3F:
default:
return GetDefaultReply(IPC_EINVAL);
return IPCReply(IPC_EINVAL);
}
}

IPCCommandResult ESDevice::GetConsumption(const IOCtlVRequest& request)
IPCReply ESDevice::GetConsumption(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 2))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

// This is at least what crediar's ES module does
Memory::Write_U32(0, request.io_vectors[1].address);
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETCONSUMPTION");
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::Launch(const IOCtlVRequest& request)
std::optional<IPCReply> ESDevice::Launch(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const u32 view = Memory::Read_U32(request.in_vectors[1].address);
@@ -598,41 +598,41 @@ IPCCommandResult ESDevice::Launch(const IOCtlVRequest& request)

// Prevent loading installed IOSes that are not emulated.
if (!IsEmulated(title_id))
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

// IOS replies to the request through the mailbox on failure, and acks if the launch succeeds.
// Note: Launch will potentially reset the whole IOS state -- including this ES instance.
if (!LaunchTitle(title_id))
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

// ES_LAUNCH involves restarting IOS, which results in two acknowledgements in a row
// (one from the previous IOS for this IPC request, and one from the new one as it boots).
// Nothing should be written to the command buffer if the launch succeeded for obvious reasons.
return GetNoReply();
return std::nullopt;
}

IPCCommandResult ESDevice::LaunchBC(const IOCtlVRequest& request)
std::optional<IPCReply> ESDevice::LaunchBC(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

// Here, IOS checks the clock speed and prevents ioctlv 0x25 from being used in GC mode.
// An alternative way to do this is to check whether the current active IOS is MIOS.
if (m_ios.GetVersion() == 0x101)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

if (!LaunchTitle(0x0000000100000100))
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

return GetNoReply();
return std::nullopt;
}

// This is technically an ioctlv in IOS's ES, but it is an internal API which cannot be
// used from the PowerPC (for unpatched and up-to-date IOSes anyway).
// So we block access to it from the IPC interface.
IPCCommandResult ESDevice::DIVerify(const IOCtlVRequest& request)
IPCReply ESDevice::DIVerify(const IOCtlVRequest& request)
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

static ReturnCode WriteTmdForDiVerify(FS::FileSystem* fs, const ES::TMDReader& tmd)
@@ -796,36 +796,36 @@ ReturnCode ESDevice::SetUpStreamKey(const u32 uid, const u8* ticket_view, const
&ticket_bytes[offsetof(ES::Ticket, title_key)], PID_ES);
}

IPCCommandResult ESDevice::SetUpStreamKey(const Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::SetUpStreamKey(const Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1) ||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
!ES::IsValidTMDSize(request.in_vectors[1].size) || request.io_vectors[0].size != sizeof(u32))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

std::vector<u8> tmd_bytes(request.in_vectors[1].size);
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[1].address, tmd_bytes.size());
const ES::TMDReader tmd{std::move(tmd_bytes)};

if (!tmd.IsValid())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u32 handle;
const ReturnCode ret =
SetUpStreamKey(context.uid, Memory::GetPointer(request.in_vectors[0].address), tmd, &handle);
Memory::Write_U32(handle, request.io_vectors[0].address);
return GetDefaultReply(ret);
return IPCReply(ret);
}

IPCCommandResult ESDevice::DeleteStreamKey(const IOCtlVRequest& request)
IPCReply ESDevice::DeleteStreamKey(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u32 handle = Memory::Read_U32(request.in_vectors[0].address);
return GetDefaultReply(m_ios.GetIOSC().DeleteObject(handle, PID_ES));
return IPCReply(m_ios.GetIOSC().DeleteObject(handle, PID_ES));
}

bool ESDevice::IsActiveTitlePermittedByTicket(const u8* ticket_view) const
@@ -48,9 +48,9 @@ class ESDevice final : public Device

void DoState(PointerWrap& p) override;

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

struct TitleImportExportContext
{
@@ -261,84 +261,84 @@ class ESDevice final : public Device
using ContextArray = std::array<Context, 3>;

// Title management
IPCCommandResult ImportTicket(const IOCtlVRequest& request);
IPCCommandResult ImportTmd(Context& context, const IOCtlVRequest& request);
IPCCommandResult ImportTitleInit(Context& context, const IOCtlVRequest& request);
IPCCommandResult ImportContentBegin(Context& context, const IOCtlVRequest& request);
IPCCommandResult ImportContentData(Context& context, const IOCtlVRequest& request);
IPCCommandResult ImportContentEnd(Context& context, const IOCtlVRequest& request);
IPCCommandResult ImportTitleDone(Context& context, const IOCtlVRequest& request);
IPCCommandResult ImportTitleCancel(Context& context, const IOCtlVRequest& request);
IPCCommandResult ExportTitleInit(Context& context, const IOCtlVRequest& request);
IPCCommandResult ExportContentBegin(Context& context, const IOCtlVRequest& request);
IPCCommandResult ExportContentData(Context& context, const IOCtlVRequest& request);
IPCCommandResult ExportContentEnd(Context& context, const IOCtlVRequest& request);
IPCCommandResult ExportTitleDone(Context& context, const IOCtlVRequest& request);
IPCCommandResult DeleteTitle(const IOCtlVRequest& request);
IPCCommandResult DeleteTitleContent(const IOCtlVRequest& request);
IPCCommandResult DeleteTicket(const IOCtlVRequest& request);
IPCCommandResult DeleteSharedContent(const IOCtlVRequest& request);
IPCCommandResult DeleteContent(const IOCtlVRequest& request);
IPCReply ImportTicket(const IOCtlVRequest& request);
IPCReply ImportTmd(Context& context, const IOCtlVRequest& request);
IPCReply ImportTitleInit(Context& context, const IOCtlVRequest& request);
IPCReply ImportContentBegin(Context& context, const IOCtlVRequest& request);
IPCReply ImportContentData(Context& context, const IOCtlVRequest& request);
IPCReply ImportContentEnd(Context& context, const IOCtlVRequest& request);
IPCReply ImportTitleDone(Context& context, const IOCtlVRequest& request);
IPCReply ImportTitleCancel(Context& context, const IOCtlVRequest& request);
IPCReply ExportTitleInit(Context& context, const IOCtlVRequest& request);
IPCReply ExportContentBegin(Context& context, const IOCtlVRequest& request);
IPCReply ExportContentData(Context& context, const IOCtlVRequest& request);
IPCReply ExportContentEnd(Context& context, const IOCtlVRequest& request);
IPCReply ExportTitleDone(Context& context, const IOCtlVRequest& request);
IPCReply DeleteTitle(const IOCtlVRequest& request);
IPCReply DeleteTitleContent(const IOCtlVRequest& request);
IPCReply DeleteTicket(const IOCtlVRequest& request);
IPCReply DeleteSharedContent(const IOCtlVRequest& request);
IPCReply DeleteContent(const IOCtlVRequest& request);

// Device identity and encryption
IPCCommandResult GetDeviceId(const IOCtlVRequest& request);
IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request);
IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request);
IPCCommandResult Sign(const IOCtlVRequest& request);
IPCCommandResult VerifySign(const IOCtlVRequest& request);
IPCCommandResult Encrypt(u32 uid, const IOCtlVRequest& request);
IPCCommandResult Decrypt(u32 uid, const IOCtlVRequest& request);
IPCReply GetDeviceId(const IOCtlVRequest& request);
IPCReply GetDeviceCertificate(const IOCtlVRequest& request);
IPCReply CheckKoreaRegion(const IOCtlVRequest& request);
IPCReply Sign(const IOCtlVRequest& request);
IPCReply VerifySign(const IOCtlVRequest& request);
IPCReply Encrypt(u32 uid, const IOCtlVRequest& request);
IPCReply Decrypt(u32 uid, const IOCtlVRequest& request);

// Misc
IPCCommandResult SetUID(u32 uid, const IOCtlVRequest& request);
IPCCommandResult GetTitleDirectory(const IOCtlVRequest& request);
IPCCommandResult GetTitleId(const IOCtlVRequest& request);
IPCCommandResult GetConsumption(const IOCtlVRequest& request);
IPCCommandResult Launch(const IOCtlVRequest& request);
IPCCommandResult LaunchBC(const IOCtlVRequest& request);
IPCCommandResult DIVerify(const IOCtlVRequest& request);
IPCCommandResult SetUpStreamKey(const Context& context, const IOCtlVRequest& request);
IPCCommandResult DeleteStreamKey(const IOCtlVRequest& request);
IPCReply SetUID(u32 uid, const IOCtlVRequest& request);
IPCReply GetTitleDirectory(const IOCtlVRequest& request);
IPCReply GetTitleId(const IOCtlVRequest& request);
IPCReply GetConsumption(const IOCtlVRequest& request);
std::optional<IPCReply> Launch(const IOCtlVRequest& request);
std::optional<IPCReply> LaunchBC(const IOCtlVRequest& request);
IPCReply DIVerify(const IOCtlVRequest& request);
IPCReply SetUpStreamKey(const Context& context, const IOCtlVRequest& request);
IPCReply DeleteStreamKey(const IOCtlVRequest& request);

// Title contents
IPCCommandResult OpenActiveTitleContent(u32 uid, const IOCtlVRequest& request);
IPCCommandResult OpenContent(u32 uid, const IOCtlVRequest& request);
IPCCommandResult ReadContent(u32 uid, const IOCtlVRequest& request);
IPCCommandResult CloseContent(u32 uid, const IOCtlVRequest& request);
IPCCommandResult SeekContent(u32 uid, const IOCtlVRequest& request);
IPCReply OpenActiveTitleContent(u32 uid, const IOCtlVRequest& request);
IPCReply OpenContent(u32 uid, const IOCtlVRequest& request);
IPCReply ReadContent(u32 uid, const IOCtlVRequest& request);
IPCReply CloseContent(u32 uid, const IOCtlVRequest& request);
IPCReply SeekContent(u32 uid, const IOCtlVRequest& request);

// Title information
IPCCommandResult GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request);
IPCCommandResult GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request);
IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request);
IPCCommandResult GetOwnedTitles(const IOCtlVRequest& request);
IPCCommandResult GetTitleCount(const IOCtlVRequest& request);
IPCCommandResult GetTitles(const IOCtlVRequest& request);
IPCCommandResult GetBoot2Version(const IOCtlVRequest& request);
IPCCommandResult GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlVRequest& request);
IPCCommandResult GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request);
IPCCommandResult GetStoredContentsCount(const IOCtlVRequest& request);
IPCCommandResult GetStoredContents(const IOCtlVRequest& request);
IPCCommandResult GetTMDStoredContentsCount(const IOCtlVRequest& request);
IPCCommandResult GetTMDStoredContents(const IOCtlVRequest& request);
IPCCommandResult GetStoredTMDSize(const IOCtlVRequest& request);
IPCCommandResult GetStoredTMD(const IOCtlVRequest& request);
IPCCommandResult GetSharedContentsCount(const IOCtlVRequest& request) const;
IPCCommandResult GetSharedContents(const IOCtlVRequest& request) const;
IPCReply GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request);
IPCReply GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request);
IPCReply GetOwnedTitleCount(const IOCtlVRequest& request);
IPCReply GetOwnedTitles(const IOCtlVRequest& request);
IPCReply GetTitleCount(const IOCtlVRequest& request);
IPCReply GetTitles(const IOCtlVRequest& request);
IPCReply GetBoot2Version(const IOCtlVRequest& request);
IPCReply GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlVRequest& request);
IPCReply GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request);
IPCReply GetStoredContentsCount(const IOCtlVRequest& request);
IPCReply GetStoredContents(const IOCtlVRequest& request);
IPCReply GetTMDStoredContentsCount(const IOCtlVRequest& request);
IPCReply GetTMDStoredContents(const IOCtlVRequest& request);
IPCReply GetStoredTMDSize(const IOCtlVRequest& request);
IPCReply GetStoredTMD(const IOCtlVRequest& request);
IPCReply GetSharedContentsCount(const IOCtlVRequest& request) const;
IPCReply GetSharedContents(const IOCtlVRequest& request) const;

// Views for tickets and TMDs
IPCCommandResult GetTicketViewCount(const IOCtlVRequest& request);
IPCCommandResult GetTicketViews(const IOCtlVRequest& request);
IPCCommandResult GetV0TicketFromView(const IOCtlVRequest& request);
IPCCommandResult GetTicketSizeFromView(const IOCtlVRequest& request);
IPCCommandResult GetTicketFromView(const IOCtlVRequest& request);
IPCCommandResult GetTMDViewSize(const IOCtlVRequest& request);
IPCCommandResult GetTMDViews(const IOCtlVRequest& request);
IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);
IPCCommandResult DIGetTMDViewSize(const IOCtlVRequest& request);
IPCCommandResult DIGetTMDView(const IOCtlVRequest& request);
IPCCommandResult DIGetTMDSize(const IOCtlVRequest& request);
IPCCommandResult DIGetTMD(const IOCtlVRequest& request);
IPCReply GetTicketViewCount(const IOCtlVRequest& request);
IPCReply GetTicketViews(const IOCtlVRequest& request);
IPCReply GetV0TicketFromView(const IOCtlVRequest& request);
IPCReply GetTicketSizeFromView(const IOCtlVRequest& request);
IPCReply GetTicketFromView(const IOCtlVRequest& request);
IPCReply GetTMDViewSize(const IOCtlVRequest& request);
IPCReply GetTMDViews(const IOCtlVRequest& request);
IPCReply DIGetTicketView(const IOCtlVRequest& request);
IPCReply DIGetTMDViewSize(const IOCtlVRequest& request);
IPCReply DIGetTMDView(const IOCtlVRequest& request);
IPCReply DIGetTMDSize(const IOCtlVRequest& request);
IPCReply DIGetTMD(const IOCtlVRequest& request);

ContextArray::iterator FindActiveContext(s32 fd);
ContextArray::iterator FindInactiveContext();
@@ -27,23 +27,23 @@ ReturnCode ESDevice::GetDeviceId(u32* device_id) const
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::GetDeviceId(const IOCtlVRequest& request)
IPCReply ESDevice::GetDeviceId(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u32 device_id;
const ReturnCode ret = GetDeviceId(&device_id);
if (ret != IPC_SUCCESS)
return GetDefaultReply(ret);
return IPCReply(ret);
Memory::Write_U32(device_id, request.io_vectors[0].address);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
IPCReply ESDevice::Encrypt(u32 uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(3, 2))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
u8* source = Memory::GetPointer(request.in_vectors[2].address);
@@ -54,13 +54,13 @@ IPCCommandResult 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);
return GetDefaultReply(ret);
return IPCReply(ret);
}

IPCCommandResult ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
IPCReply ESDevice::Decrypt(u32 uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(3, 2))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
u8* source = Memory::GetPointer(request.in_vectors[2].address);
@@ -71,38 +71,38 @@ IPCCommandResult 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);
return GetDefaultReply(ret);
return IPCReply(ret);
}

IPCCommandResult ESDevice::CheckKoreaRegion(const IOCtlVRequest& request)
IPCReply ESDevice::CheckKoreaRegion(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

// note by DacoTaco : name is unknown, I just tried to name it SOMETHING.
// IOS70 has this to let system menu 4.2 check if the console is region changed. it returns
// -1017
// if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
INFO_LOG_FMT(IOS_ES, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys.");
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

IPCCommandResult ESDevice::GetDeviceCertificate(const IOCtlVRequest& request)
IPCReply ESDevice::GetDeviceCertificate(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 0x180)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETDEVICECERT");

const IOS::CertECC cert = m_ios.GetIOSC().GetDeviceCertificate();
Memory::CopyToEmu(request.io_vectors[0].address, &cert, sizeof(cert));
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::Sign(const IOCtlVRequest& request)
IPCReply ESDevice::Sign(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 2))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

INFO_LOG_FMT(IOS_ES, "IOCTL_ES_SIGN");
u8* ap_cert_out = Memory::GetPointer(request.io_vectors[1].address);
@@ -111,10 +111,10 @@ IPCCommandResult ESDevice::Sign(const IOCtlVRequest& request)
u8* sig_out = Memory::GetPointer(request.io_vectors[0].address);

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

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

ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
@@ -185,12 +185,12 @@ ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::VerifySign(const IOCtlVRequest& request)
IPCReply ESDevice::VerifySign(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(3, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
if (request.in_vectors[1].size != sizeof(Common::ec::Signature))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

std::vector<u8> hash(request.in_vectors[0].size);
Memory::CopyFromEmu(hash.data(), request.in_vectors[0].address, hash.size());
@@ -201,6 +201,6 @@ IPCCommandResult 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 GetDefaultReply(VerifySign(hash, ecc_signature, certs));
return IPCReply(VerifySign(hash, ecc_signature, certs));
}
} // namespace IOS::HLE
@@ -46,13 +46,13 @@ s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid)
return FS_EFDEXHAUSTED;
}

IPCCommandResult ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)
IPCReply ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(3, 0) || request.in_vectors[0].size != sizeof(u64) ||
request.in_vectors[1].size != sizeof(ES::TicketView) ||
request.in_vectors[2].size != sizeof(u32))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
@@ -61,27 +61,27 @@ IPCCommandResult ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request)

const auto tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

return GetDefaultReply(OpenContent(tmd, content_index, uid));
return IPCReply(OpenContent(tmd, content_index, uid));
}

IPCCommandResult ESDevice::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& request)
IPCReply ESDevice::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u32 content_index = Memory::Read_U32(request.in_vectors[0].address);

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

ES::UIDSys uid_map{m_ios.GetFS()};
const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId());
if (caller_uid != 0 && caller_uid != uid)
return GetDefaultReply(ES_EACCES);
return IPCReply(ES_EACCES);

return GetDefaultReply(OpenContent(m_title_context.tmd, content_index, caller_uid));
return IPCReply(OpenContent(m_title_context.tmd, content_index, caller_uid));
}

s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid)
@@ -99,16 +99,16 @@ s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid)
return result.Succeeded() ? *result : FS::ConvertResult(result.Error());
}

IPCCommandResult ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

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;

return GetDefaultReply(ReadContent(cfd, Memory::GetPointer(addr), size, uid));
return IPCReply(ReadContent(cfd, Memory::GetPointer(addr), size, uid));
}

ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid)
@@ -128,13 +128,13 @@ ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid)
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::CloseContent(u32 uid, const IOCtlVRequest& request)
IPCReply ESDevice::CloseContent(u32 uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
return GetDefaultReply(CloseContent(cfd, uid));
return IPCReply(CloseContent(cfd, uid));
}

s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid)
@@ -152,15 +152,15 @@ s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid)
return result.Succeeded() ? *result : FS::ConvertResult(result.Error());
}

IPCCommandResult ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
IPCReply ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(3, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u32 cfd = Memory::Read_U32(request.in_vectors[0].address);
const u32 offset = Memory::Read_U32(request.in_vectors[1].address);
const SeekMode mode = static_cast<SeekMode>(Memory::Read_U32(request.in_vectors[2].address));

return GetDefaultReply(SeekContent(cfd, offset, mode, uid));
return IPCReply(SeekContent(cfd, offset, mode, uid));
}
} // namespace IOS::HLE
@@ -16,227 +16,225 @@ namespace IOS::HLE
{
// Used by the GetStoredContents ioctlvs. This assumes that the first output vector
// is used for the content count (u32).
IPCCommandResult ESDevice::GetStoredContentsCount(const ES::TMDReader& tmd,
const IOCtlVRequest& request)
IPCReply ESDevice::GetStoredContentsCount(const ES::TMDReader& tmd, const IOCtlVRequest& request)
{
if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u16 num_contents = static_cast<u16>(GetStoredContentsFromTMD(tmd).size());
Memory::Write_U32(num_contents, request.io_vectors[0].address);

INFO_LOG_FMT(IOS_ES, "GetStoredContentsCount ({:#x}): {} content(s) for {:016x}",
request.request, num_contents, tmd.GetTitleId());
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

// Used by the GetStoredContents ioctlvs. This assumes that the second input vector is used
// for the content count and the output vector is used to store a list of content IDs (u32s).
IPCCommandResult ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request)
IPCReply ESDevice::GetStoredContents(const ES::TMDReader& tmd, const IOCtlVRequest& request)
{
if (!tmd.IsValid())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

if (request.in_vectors[1].size != sizeof(u32) ||
request.io_vectors[0].size != Memory::Read_U32(request.in_vectors[1].address) * sizeof(u32))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

const auto contents = 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));

return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::GetStoredContentsCount(const IOCtlVRequest& request)
IPCReply ESDevice::GetStoredContentsCount(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u64))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);
return GetStoredContentsCount(tmd, request);
}

IPCCommandResult ESDevice::GetStoredContents(const IOCtlVRequest& request)
IPCReply ESDevice::GetStoredContents(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);
return GetStoredContents(tmd, request);
}

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

std::vector<u8> tmd_bytes(request.in_vectors[0].size);
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());
return GetStoredContentsCount(ES::TMDReader{std::move(tmd_bytes)}, request);
}

IPCCommandResult ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
IPCReply ESDevice::GetTMDStoredContents(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

std::vector<u8> tmd_bytes(request.in_vectors[0].size);
Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size());

const ES::TMDReader tmd{std::move(tmd_bytes)};
if (!tmd.IsValid())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

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

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

return GetStoredContents(tmd, request);
}

IPCCommandResult ESDevice::GetTitleCount(const std::vector<u64>& titles,
const IOCtlVRequest& request)
IPCReply ESDevice::GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

Memory::Write_U32(static_cast<u32>(titles.size()), request.io_vectors[0].address);

return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request)
IPCReply ESDevice::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

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++)
{
Memory::Write_U64(titles[i], request.io_vectors[0].address + static_cast<u32>(i) * sizeof(u64));
INFO_LOG_FMT(IOS_ES, " title {:016x}", titles[i]);
}
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

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

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

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

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

const u32 tmd_size = static_cast<u32>(tmd.GetBytes().size());
Memory::Write_U32(tmd_size, request.io_vectors[0].address);

INFO_LOG_FMT(IOS_ES, "GetStoredTMDSize: {} bytes for {:016x}", tmd_size, title_id);

return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::GetStoredTMD(const IOCtlVRequest& request)
IPCReply ESDevice::GetStoredTMD(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const ES::TMDReader tmd = FindInstalledTMD(title_id);
if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

// TODO: actually use this param in when writing to the outbuffer :/
const u32 MaxCount = Memory::Read_U32(request.in_vectors[1].address);

const std::vector<u8>& raw_tmd = tmd.GetBytes();
if (raw_tmd.size() != request.io_vectors[0].size)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());

INFO_LOG_FMT(IOS_ES, "GetStoredTMD: title {:016x} (buffer size: {})", title_id, MaxCount);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

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

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

IPCCommandResult ESDevice::GetBoot2Version(const IOCtlVRequest& request)
IPCReply ESDevice::GetBoot2Version(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETBOOT2VERSION");

// as of 26/02/2012, this was latest bootmii version
Memory::Write_U32(4, request.io_vectors[0].address);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::GetSharedContentsCount(const IOCtlVRequest& request) const
IPCReply ESDevice::GetSharedContentsCount(const IOCtlVRequest& request) const
{
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u32 count = GetSharedContentsCount();
Memory::Write_U32(count, request.io_vectors[0].address);

INFO_LOG_FMT(IOS_ES, "GetSharedContentsCount: {} contents", count);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::GetSharedContents(const IOCtlVRequest& request) const
IPCReply ESDevice::GetSharedContents(const IOCtlVRequest& request) const
{
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u32 max_count = Memory::Read_U32(request.in_vectors[0].address);
if (request.io_vectors[0].size != 20 * max_count)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

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

INFO_LOG_FMT(IOS_ES, "GetSharedContents: {} contents ({} requested)", count, max_count);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}
} // namespace IOS::HLE
@@ -93,16 +93,16 @@ ReturnCode ESDevice::ImportTicket(const std::vector<u8>& ticket_bytes,
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ImportTicket(const IOCtlVRequest& request)
IPCReply ESDevice::ImportTicket(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(3, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

std::vector<u8> bytes(request.in_vectors[0].size);
Memory::CopyFromEmu(bytes.data(), request.in_vectors[0].address, request.in_vectors[0].size);
std::vector<u8> cert_chain(request.in_vectors[1].size);
Memory::CopyFromEmu(cert_chain.data(), request.in_vectors[1].address, request.in_vectors[1].size);
return GetDefaultReply(ImportTicket(bytes, cert_chain));
return IPCReply(ImportTicket(bytes, cert_chain));
}

constexpr std::array<u8, 16> NULL_KEY{};
@@ -180,18 +180,18 @@ ReturnCode ESDevice::ImportTmd(Context& context, const std::vector<u8>& tmd_byte
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ImportTmd(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ImportTmd(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

if (!ES::IsValidTMDSize(request.in_vectors[0].size))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

std::vector<u8> tmd(request.in_vectors[0].size);
Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size);
return GetDefaultReply(ImportTmd(context, tmd, m_title_context.tmd.GetTitleId(),
m_title_context.tmd.GetTitleFlags()));
return IPCReply(ImportTmd(context, tmd, m_title_context.tmd.GetTitleId(),
m_title_context.tmd.GetTitleFlags()));
}

static ReturnCode InitTitleImportKey(const std::vector<u8>& ticket_bytes, IOSC& iosc,
@@ -266,19 +266,19 @@ ReturnCode ESDevice::ImportTitleInit(Context& context, const std::vector<u8>& tm
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ImportTitleInit(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ImportTitleInit(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(4, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

if (!ES::IsValidTMDSize(request.in_vectors[0].size))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

std::vector<u8> tmd(request.in_vectors[0].size);
Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size);
std::vector<u8> certs(request.in_vectors[1].size);
Memory::CopyFromEmu(certs.data(), request.in_vectors[1].address, request.in_vectors[1].size);
return GetDefaultReply(ImportTitleInit(context, tmd, certs));
return IPCReply(ImportTitleInit(context, tmd, certs));
}

ReturnCode ESDevice::ImportContentBegin(Context& context, u64 title_id, u32 content_id)
@@ -324,14 +324,14 @@ ReturnCode ESDevice::ImportContentBegin(Context& context, u64 title_id, u32 cont
return static_cast<ReturnCode>(content_fd);
}

IPCCommandResult ESDevice::ImportContentBegin(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ImportContentBegin(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
u32 content_id = Memory::Read_U32(request.in_vectors[1].address);
return GetDefaultReply(ImportContentBegin(context, title_id, content_id));
return IPCReply(ImportContentBegin(context, title_id, content_id));
}

ReturnCode ESDevice::ImportContentData(Context& context, u32 content_fd, const u8* data,
@@ -343,15 +343,14 @@ ReturnCode ESDevice::ImportContentData(Context& context, u32 content_fd, const u
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ImportContentData(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ImportContentData(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
u8* data_start = Memory::GetPointer(request.in_vectors[1].address);
return GetDefaultReply(
ImportContentData(context, content_fd, data_start, request.in_vectors[1].size));
return IPCReply(ImportContentData(context, content_fd, data_start, request.in_vectors[1].size));
}

static bool CheckIfContentHashMatches(const std::vector<u8>& content, const ES::Content& info)
@@ -429,13 +428,13 @@ ReturnCode ESDevice::ImportContentEnd(Context& context, u32 content_fd)
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ImportContentEnd(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ImportContentEnd(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
return GetDefaultReply(ImportContentEnd(context, content_fd));
return IPCReply(ImportContentEnd(context, content_fd));
}

static bool HasAllRequiredContents(Kernel& ios, const ES::TMDReader& tmd)
@@ -492,12 +491,12 @@ ReturnCode ESDevice::ImportTitleDone(Context& context)
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ImportTitleDone(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ImportTitleDone(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

return GetDefaultReply(ImportTitleDone(context));
return IPCReply(ImportTitleDone(context));
}

ReturnCode ESDevice::ImportTitleCancel(Context& context)
@@ -518,12 +517,12 @@ ReturnCode ESDevice::ImportTitleCancel(Context& context)
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ImportTitleCancel(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ImportTitleCancel(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 0))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

return GetDefaultReply(ImportTitleCancel(context));
return IPCReply(ImportTitleCancel(context));
}

static bool CanDeleteTitle(u64 title_id)
@@ -541,13 +540,13 @@ ReturnCode ESDevice::DeleteTitle(u64 title_id)
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, title_dir));
}

IPCCommandResult ESDevice::DeleteTitle(const IOCtlVRequest& request)
IPCReply ESDevice::DeleteTitle(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
return GetDefaultReply(DeleteTitle(title_id));
return IPCReply(DeleteTitle(title_id));
}

ReturnCode ESDevice::DeleteTicket(const u8* ticket_view)
@@ -590,14 +589,14 @@ ReturnCode ESDevice::DeleteTicket(const u8* ticket_view)
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::DeleteTicket(const IOCtlVRequest& request)
IPCReply ESDevice::DeleteTicket(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) ||
request.in_vectors[0].size != sizeof(ES::TicketView))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}
return GetDefaultReply(DeleteTicket(Memory::GetPointer(request.in_vectors[0].address)));
return IPCReply(DeleteTicket(Memory::GetPointer(request.in_vectors[0].address)));
}

ReturnCode ESDevice::DeleteTitleContent(u64 title_id) const
@@ -619,11 +618,11 @@ ReturnCode ESDevice::DeleteTitleContent(u64 title_id) const
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::DeleteTitleContent(const IOCtlVRequest& request)
IPCReply ESDevice::DeleteTitleContent(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u64))
return GetDefaultReply(ES_EINVAL);
return GetDefaultReply(DeleteTitleContent(Memory::Read_U64(request.in_vectors[0].address)));
return IPCReply(ES_EINVAL);
return IPCReply(DeleteTitleContent(Memory::Read_U64(request.in_vectors[0].address)));
}

ReturnCode ESDevice::DeleteContent(u64 title_id, u32 content_id) const
@@ -644,15 +643,15 @@ ReturnCode ESDevice::DeleteContent(u64 title_id, u32 content_id) const
return FS::ConvertResult(m_ios.GetFS()->Delete(PID_KERNEL, PID_KERNEL, path));
}

IPCCommandResult ESDevice::DeleteContent(const IOCtlVRequest& request)
IPCReply ESDevice::DeleteContent(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 0) || request.in_vectors[0].size != sizeof(u64) ||
request.in_vectors[1].size != sizeof(u32))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}
return GetDefaultReply(DeleteContent(Memory::Read_U64(request.in_vectors[0].address),
Memory::Read_U32(request.in_vectors[1].address)));
return IPCReply(DeleteContent(Memory::Read_U64(request.in_vectors[0].address),
Memory::Read_U32(request.in_vectors[1].address)));
}

ReturnCode ESDevice::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u32 tmd_size,
@@ -684,18 +683,18 @@ ReturnCode ESDevice::ExportTitleInit(Context& context, u64 title_id, u8* tmd_byt
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ExportTitleInit(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ExportTitleInit(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 8)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
u8* tmd_bytes = Memory::GetPointer(request.io_vectors[0].address);
const u32 tmd_size = request.io_vectors[0].size;

return GetDefaultReply(ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
m_title_context.tmd.GetTitleId(),
m_title_context.tmd.GetTitleFlags()));
return IPCReply(ExportTitleInit(context, title_id, tmd_bytes, tmd_size,
m_title_context.tmd.GetTitleId(),
m_title_context.tmd.GetTitleFlags()));
}

ReturnCode ESDevice::ExportContentBegin(Context& context, u64 title_id, u32 content_id)
@@ -729,16 +728,16 @@ ReturnCode ESDevice::ExportContentBegin(Context& context, u64 title_id, u32 cont
return static_cast<ReturnCode>(ret);
}

IPCCommandResult ESDevice::ExportContentBegin(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ExportContentBegin(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 0) || request.in_vectors[0].size != 8 ||
request.in_vectors[1].size != 4)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 title_id = Memory::Read_U64(request.in_vectors[0].address);
const u32 content_id = Memory::Read_U32(request.in_vectors[1].address);

return GetDefaultReply(ExportContentBegin(context, title_id, content_id));
return IPCReply(ExportContentBegin(context, title_id, content_id));
}

ReturnCode ESDevice::ExportContentData(Context& context, u32 content_fd, u8* data, u32 data_size)
@@ -775,19 +774,19 @@ ReturnCode ESDevice::ExportContentData(Context& context, u32 content_fd, u8* dat
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ExportContentData(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ExportContentData(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 4 ||
request.io_vectors[0].size == 0)
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
u8* data = Memory::GetPointer(request.io_vectors[0].address);
const u32 bytes_to_read = request.io_vectors[0].size;

return GetDefaultReply(ExportContentData(context, content_fd, data, bytes_to_read));
return IPCReply(ExportContentData(context, content_fd, data, bytes_to_read));
}

ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd)
@@ -797,13 +796,13 @@ ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd)
return CloseContent(content_fd, 0);
}

IPCCommandResult ESDevice::ExportContentEnd(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ExportContentEnd(Context& context, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 4)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address);
return GetDefaultReply(ExportContentEnd(context, content_fd));
return IPCReply(ExportContentEnd(context, content_fd));
}

ReturnCode ESDevice::ExportTitleDone(Context& context)
@@ -812,9 +811,9 @@ ReturnCode ESDevice::ExportTitleDone(Context& context)
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::ExportTitleDone(Context& context, const IOCtlVRequest& request)
IPCReply ESDevice::ExportTitleDone(Context& context, const IOCtlVRequest& request)
{
return GetDefaultReply(ExportTitleDone(context));
return IPCReply(ExportTitleDone(context));
}

ReturnCode ESDevice::DeleteSharedContent(const std::array<u8, 20>& sha1) const
@@ -854,12 +853,12 @@ ReturnCode ESDevice::DeleteSharedContent(const std::array<u8, 20>& sha1) const
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::DeleteSharedContent(const IOCtlVRequest& request)
IPCReply ESDevice::DeleteSharedContent(const IOCtlVRequest& request)
{
std::array<u8, 20> sha1;
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sha1.size())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
Memory::CopyFromEmu(sha1.data(), request.in_vectors[0].address, request.in_vectors[0].size);
return GetDefaultReply(DeleteSharedContent(sha1));
return IPCReply(DeleteSharedContent(sha1));
}
} // namespace IOS::HLE
@@ -36,10 +36,10 @@ static bool ShouldReturnFakeViewsForIOSes(u64 title_id, const TitleContext& cont
(ios && SConfig::GetInstance().m_disc_booted_from_game_list && disc_title);
}

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

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

@@ -61,13 +61,13 @@ IPCCommandResult ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
view_count);

Memory::Write_U32(view_count, request.io_vectors[0].address);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::GetTicketViews(const IOCtlVRequest& request)
IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
const u32 maxViews = Memory::Read_U32(request.in_vectors[1].address);
@@ -96,7 +96,7 @@ IPCCommandResult ESDevice::GetTicketViews(const IOCtlVRequest& request)

INFO_LOG_FMT(IOS_ES, "IOCTL_ES_GETVIEWS for titleID: {:016x} (MaxViews = {})", TitleID, maxViews);

return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

ReturnCode ESDevice::GetV0TicketFromView(const u8* ticket_view, u8* ticket) const
@@ -157,106 +157,106 @@ ReturnCode ESDevice::GetTicketFromView(const u8* ticket_view, u8* ticket, u32* t
return IPC_SUCCESS;
}

IPCCommandResult ESDevice::GetV0TicketFromView(const IOCtlVRequest& request)
IPCReply ESDevice::GetV0TicketFromView(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1) ||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
request.io_vectors[0].size != sizeof(ES::Ticket))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}
return GetDefaultReply(GetV0TicketFromView(Memory::GetPointer(request.in_vectors[0].address),
Memory::GetPointer(request.io_vectors[0].address)));
return IPCReply(GetV0TicketFromView(Memory::GetPointer(request.in_vectors[0].address),
Memory::GetPointer(request.io_vectors[0].address)));
}

IPCCommandResult ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
IPCReply ESDevice::GetTicketSizeFromView(const IOCtlVRequest& request)
{
u32 ticket_size = 0;
if (!request.HasNumberOfValidVectors(1, 1) ||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
request.io_vectors[0].size != sizeof(ticket_size))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}
const ReturnCode ret =
GetTicketFromView(Memory::GetPointer(request.in_vectors[0].address), nullptr, &ticket_size);
Memory::Write_U32(ticket_size, request.io_vectors[0].address);
return GetDefaultReply(ret);
return IPCReply(ret);
}

IPCCommandResult ESDevice::GetTicketFromView(const IOCtlVRequest& request)
IPCReply ESDevice::GetTicketFromView(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1) ||
request.in_vectors[0].size != sizeof(ES::TicketView) ||
request.in_vectors[1].size != sizeof(u32))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

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

return GetDefaultReply(GetTicketFromView(Memory::GetPointer(request.in_vectors[0].address),
Memory::GetPointer(request.io_vectors[0].address),
&ticket_size));
return IPCReply(GetTicketFromView(Memory::GetPointer(request.in_vectors[0].address),
Memory::GetPointer(request.io_vectors[0].address),
&ticket_size));
}

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

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

if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

const u32 view_size = static_cast<u32>(tmd.GetRawView().size());
Memory::Write_U32(view_size, request.io_vectors[0].address);

INFO_LOG_FMT(IOS_ES, "GetTMDViewSize: {} bytes for title {:016x}", view_size, TitleID);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::GetTMDViews(const IOCtlVRequest& request)
IPCReply ESDevice::GetTMDViews(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1) ||
request.in_vectors[0].size != sizeof(ES::TMDHeader::title_id) ||
request.in_vectors[1].size != sizeof(u32) ||
Memory::Read_U32(request.in_vectors[1].address) != request.io_vectors[0].size)
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

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

if (!tmd.IsValid())
return GetDefaultReply(FS_ENOENT);
return IPCReply(FS_ENOENT);

const std::vector<u8> raw_view = tmd.GetRawView();
if (request.io_vectors[0].size < raw_view.size())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

Memory::CopyToEmu(request.io_vectors[0].address, raw_view.data(), raw_view.size());

INFO_LOG_FMT(IOS_ES, "GetTMDView: {} bytes for title {:016x}", raw_view.size(), title_id);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

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

// Sanity check the TMD size.
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

if (request.io_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

const bool has_tmd = request.in_vectors[0].size != 0;
size_t tmd_view_size = 0;
@@ -270,37 +270,37 @@ IPCCommandResult ESDevice::DIGetTMDViewSize(const IOCtlVRequest& request)
// Yes, this returns -1017, not ES_INVALID_TMD.
// IOS simply checks whether the TMD has all required content entries.
if (!tmd.IsValid())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

tmd_view_size = tmd.GetRawView().size();
}
else
{
// If no TMD was passed in and no title is active, IOS returns -1017.
if (!m_title_context.active)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

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

Memory::Write_U32(static_cast<u32>(tmd_view_size), request.io_vectors[0].address);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::DIGetTMDView(const IOCtlVRequest& request)
IPCReply ESDevice::DIGetTMDView(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(2, 1))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

// Sanity check the TMD size.
if (request.in_vectors[0].size >= 4 * 1024 * 1024)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

// Check whether the TMD view size is consistent.
if (request.in_vectors[1].size != sizeof(u32) ||
Memory::Read_U32(request.in_vectors[1].address) != request.io_vectors[0].size)
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

const bool has_tmd = request.in_vectors[0].size != 0;
@@ -313,39 +313,39 @@ IPCCommandResult ESDevice::DIGetTMDView(const IOCtlVRequest& request)
const ES::TMDReader tmd{std::move(tmd_bytes)};

if (!tmd.IsValid())
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

tmd_view = tmd.GetRawView();
}
else
{
// If no TMD was passed in and no title is active, IOS returns -1017.
if (!m_title_context.active)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

tmd_view = m_title_context.tmd.GetRawView();
}

if (tmd_view.size() > request.io_vectors[0].size)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

Memory::CopyToEmu(request.io_vectors[0].address, tmd_view.data(), tmd_view.size());
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::DIGetTicketView(const IOCtlVRequest& request)
IPCReply ESDevice::DIGetTicketView(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1) ||
request.io_vectors[0].size != sizeof(ES::TicketView))
{
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);
}

const bool has_ticket_vector = request.in_vectors[0].size == sizeof(ES::Ticket);

// This ioctlv takes either a signed ticket or no ticket, in which case the ticket size must be 0.
if (!has_ticket_vector && request.in_vectors[0].size != 0)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

std::vector<u8> view;

@@ -354,7 +354,7 @@ IPCCommandResult ESDevice::DIGetTicketView(const IOCtlVRequest& request)
if (!has_ticket_vector)
{
if (!m_title_context.active)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

view = m_title_context.ticket.GetRawTicketView(0);
}
@@ -368,40 +368,40 @@ IPCCommandResult ESDevice::DIGetTicketView(const IOCtlVRequest& request)
}

Memory::CopyToEmu(request.io_vectors[0].address, view.data(), view.size());
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::DIGetTMDSize(const IOCtlVRequest& request)
IPCReply ESDevice::DIGetTMDSize(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

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

Memory::Write_U32(static_cast<u32>(m_title_context.tmd.GetBytes().size()),
request.io_vectors[0].address);
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult ESDevice::DIGetTMD(const IOCtlVRequest& request)
IPCReply ESDevice::DIGetTMD(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32))
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

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

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

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

if (static_cast<u32>(tmd_bytes.size()) > tmd_size)
return GetDefaultReply(ES_EINVAL);
return IPCReply(ES_EINVAL);

Memory::CopyToEmu(request.io_vectors[0].address, tmd_bytes.data(), tmd_bytes.size());
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}
} // namespace IOS::HLE
@@ -22,10 +22,10 @@ namespace IOS::HLE
{
using namespace IOS::HLE::FS;

static IPCCommandResult GetFSReply(s32 return_value, u64 extra_tb_ticks = 0)
static IPCReply GetFSReply(s32 return_value, u64 extra_tb_ticks = 0)
{
// According to hardware tests, FS takes at least 2700 TB ticks to reply to commands.
return {return_value, true, (2700 + extra_tb_ticks) * SystemTimers::TIMER_RATIO};
return IPCReply{return_value, (2700 + extra_tb_ticks) * SystemTimers::TIMER_RATIO};
}

/// Amount of TB ticks required for a superblock write to complete.
@@ -97,13 +97,13 @@ static u64 EstimateFileLookupTicks(const std::string& path, FileLookupMode mode)
///
/// A superblock flush takes a very large amount of time, so other delays are ignored
/// to simplify the implementation as they are insignificant.
static IPCCommandResult GetReplyForSuperblockOperation(ResultCode result)
static IPCReply GetReplyForSuperblockOperation(ResultCode result)
{
const u64 ticks = result == ResultCode::Success ? SUPERBLOCK_WRITE_TICKS : 0;
return GetFSReply(ConvertResult(result), ticks);
}

IPCCommandResult FSDevice::Open(const OpenRequest& request)
std::optional<IPCReply> FSDevice::Open(const OpenRequest& request)
{
if (m_fd_map.size() >= 16)
return GetFSReply(ConvertResult(ResultCode::NoFreeHandle));
@@ -130,7 +130,7 @@ IPCCommandResult FSDevice::Open(const OpenRequest& request)
return GetFSReply(IPC_SUCCESS, ticks);
}

IPCCommandResult FSDevice::Close(u32 fd)
std::optional<IPCReply> FSDevice::Close(u32 fd)
{
u64 ticks = 0;
if (m_fd_map[fd].fs_fd != INVALID_FD)
@@ -229,7 +229,7 @@ bool FSDevice::HasCacheForFile(u32 fd, u32 offset) const
return m_cache_fd == fd && m_cache_chain_index == chain_index;
}

IPCCommandResult FSDevice::Read(const ReadWriteRequest& request)
std::optional<IPCReply> FSDevice::Read(const ReadWriteRequest& request)
{
const Handle& handle = m_fd_map[request.fd];
if (handle.fs_fd == INVALID_FD)
@@ -247,7 +247,7 @@ IPCCommandResult FSDevice::Read(const ReadWriteRequest& request)
return GetFSReply(*result, ticks);
}

IPCCommandResult FSDevice::Write(const ReadWriteRequest& request)
std::optional<IPCReply> FSDevice::Write(const ReadWriteRequest& request)
{
const Handle& handle = m_fd_map[request.fd];
if (handle.fs_fd == INVALID_FD)
@@ -265,7 +265,7 @@ IPCCommandResult FSDevice::Write(const ReadWriteRequest& request)
return GetFSReply(*result, ticks);
}

IPCCommandResult FSDevice::Seek(const SeekRequest& request)
std::optional<IPCReply> FSDevice::Seek(const SeekRequest& request)
{
const Handle& handle = m_fd_map[request.fd];
if (handle.fs_fd == INVALID_FD)
@@ -318,11 +318,11 @@ static Result<T> GetParams(const IOCtlRequest& request)
return params;
}

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

switch (request.request)
{
@@ -353,11 +353,11 @@ IPCCommandResult FSDevice::IOCtl(const IOCtlRequest& request)
}
}

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

switch (request.request)
{
@@ -370,7 +370,7 @@ IPCCommandResult FSDevice::IOCtlV(const IOCtlVRequest& request)
}
}

IPCCommandResult FSDevice::Format(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::Format(const Handle& handle, const IOCtlRequest& request)
{
if (handle.uid != 0)
return GetFSReply(ConvertResult(ResultCode::AccessDenied));
@@ -379,15 +379,15 @@ IPCCommandResult FSDevice::Format(const Handle& handle, const IOCtlRequest& requ
return GetReplyForSuperblockOperation(result);
}

IPCCommandResult FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::GetStats(const Handle& handle, const IOCtlRequest& request)
{
if (request.buffer_out_size < sizeof(ISFSNandStats))
return GetFSReply(ConvertResult(ResultCode::Invalid));

const Result<NandStats> stats = m_ios.GetFS()->GetNandStats();
LogResult(stats, "GetNandStats");
if (!stats)
return GetDefaultReply(ConvertResult(stats.Error()));
return IPCReply(ConvertResult(stats.Error()));

ISFSNandStats out;
out.cluster_size = stats->cluster_size;
@@ -398,10 +398,10 @@ IPCCommandResult FSDevice::GetStats(const Handle& handle, const IOCtlRequest& re
out.free_inodes = stats->free_inodes;
out.used_inodes = stats->used_inodes;
Memory::CopyToEmu(request.buffer_out, &out, sizeof(out));
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
if (!params)
@@ -413,7 +413,7 @@ IPCCommandResult FSDevice::CreateDirectory(const Handle& handle, const IOCtlRequ
return GetReplyForSuperblockOperation(result);
}

IPCCommandResult FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& request)
IPCReply FSDevice::ReadDirectory(const Handle& handle, const IOCtlVRequest& request)
{
if (request.in_vectors.empty() || request.in_vectors.size() != request.io_vectors.size() ||
request.in_vectors.size() > 2 || request.in_vectors[0].size != 64)
@@ -467,7 +467,7 @@ IPCCommandResult FSDevice::ReadDirectory(const Handle& handle, const IOCtlVReque
return GetFSReply(IPC_SUCCESS);
}

IPCCommandResult FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
if (!params)
@@ -479,7 +479,7 @@ IPCCommandResult FSDevice::SetAttribute(const Handle& handle, const IOCtlRequest
return GetReplyForSuperblockOperation(result);
}

IPCCommandResult FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest& request)
{
if (request.buffer_in_size < 64 || request.buffer_out_size < sizeof(ISFSParams))
return GetFSReply(ConvertResult(ResultCode::Invalid));
@@ -503,7 +503,7 @@ IPCCommandResult FSDevice::GetAttribute(const Handle& handle, const IOCtlRequest
return GetFSReply(IPC_SUCCESS, ticks);
}

IPCCommandResult FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest& request)
{
if (request.buffer_in_size < 64)
return GetFSReply(ConvertResult(ResultCode::Invalid));
@@ -514,7 +514,7 @@ IPCCommandResult FSDevice::DeleteFile(const Handle& handle, const IOCtlRequest&
return GetReplyForSuperblockOperation(result);
}

IPCCommandResult FSDevice::RenameFile(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::RenameFile(const Handle& handle, const IOCtlRequest& request)
{
if (request.buffer_in_size < 64 * 2)
return GetFSReply(ConvertResult(ResultCode::Invalid));
@@ -526,7 +526,7 @@ IPCCommandResult FSDevice::RenameFile(const Handle& handle, const IOCtlRequest&
return GetReplyForSuperblockOperation(result);
}

IPCCommandResult FSDevice::CreateFile(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::CreateFile(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
if (!params)
@@ -538,7 +538,7 @@ IPCCommandResult FSDevice::CreateFile(const Handle& handle, const IOCtlRequest&
return GetReplyForSuperblockOperation(result);
}

IPCCommandResult FSDevice::SetFileVersionControl(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::SetFileVersionControl(const Handle& handle, const IOCtlRequest& request)
{
const auto params = GetParams<ISFSParams>(request);
if (!params)
@@ -550,24 +550,24 @@ IPCCommandResult FSDevice::SetFileVersionControl(const Handle& handle, const IOC
return GetFSReply(IPC_SUCCESS);
}

IPCCommandResult FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::GetFileStats(const Handle& handle, const IOCtlRequest& request)
{
if (request.buffer_out_size < 8 || handle.fs_fd == INVALID_FD)
return GetFSReply(ConvertResult(ResultCode::Invalid));

const Result<FileStatus> status = m_ios.GetFS()->GetFileStatus(handle.fs_fd);
LogResult(status, "GetFileStatus({})", handle.name.data());
if (!status)
return GetDefaultReply(ConvertResult(status.Error()));
return IPCReply(ConvertResult(status.Error()));

ISFSFileStats out;
out.size = status->size;
out.seek_position = status->offset;
Memory::CopyToEmu(request.buffer_out, &out, sizeof(out));
return GetDefaultReply(IPC_SUCCESS);
return IPCReply(IPC_SUCCESS);
}

IPCCommandResult FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& request)
IPCReply FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(1, 2) || request.in_vectors[0].size != 64 ||
request.io_vectors[0].size != 4 || request.io_vectors[1].size != 4)
@@ -586,7 +586,7 @@ IPCCommandResult FSDevice::GetUsage(const Handle& handle, const IOCtlVRequest& r
return GetFSReply(IPC_SUCCESS);
}

IPCCommandResult FSDevice::Shutdown(const Handle& handle, const IOCtlRequest& request)
IPCReply FSDevice::Shutdown(const Handle& handle, const IOCtlRequest& request)
{
INFO_LOG_FMT(IOS_FS, "Shutdown");
return GetFSReply(IPC_SUCCESS);
@@ -26,13 +26,13 @@ class FSDevice : public Device

void DoState(PointerWrap& p) override;

IPCCommandResult Open(const OpenRequest& request) override;
IPCCommandResult Close(u32 fd) override;
IPCCommandResult Read(const ReadWriteRequest& request) override;
IPCCommandResult Write(const ReadWriteRequest& request) override;
IPCCommandResult Seek(const SeekRequest& request) override;
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
IPCCommandResult IOCtlV(const IOCtlVRequest& request) 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
@@ -62,19 +62,19 @@ class FSDevice : public Device
ISFS_IOCTL_SHUTDOWN = 13,
};

IPCCommandResult Format(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult GetStats(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult CreateDirectory(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult ReadDirectory(const Handle& handle, const IOCtlVRequest& request);
IPCCommandResult SetAttribute(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult GetAttribute(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult DeleteFile(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult RenameFile(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult CreateFile(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult SetFileVersionControl(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult GetFileStats(const Handle& handle, const IOCtlRequest& request);
IPCCommandResult GetUsage(const Handle& handle, const IOCtlVRequest& request);
IPCCommandResult Shutdown(const Handle& handle, const IOCtlRequest& request);
IPCReply Format(const Handle& handle, const IOCtlRequest& request);
IPCReply GetStats(const Handle& handle, const IOCtlRequest& request);
IPCReply CreateDirectory(const Handle& handle, const IOCtlRequest& request);
IPCReply ReadDirectory(const Handle& handle, const IOCtlVRequest& request);
IPCReply SetAttribute(const Handle& handle, const IOCtlRequest& request);
IPCReply GetAttribute(const Handle& handle, const IOCtlRequest& request);
IPCReply DeleteFile(const Handle& handle, const IOCtlRequest& request);
IPCReply RenameFile(const Handle& handle, const IOCtlRequest& request);
IPCReply CreateFile(const Handle& handle, const IOCtlRequest& request);
IPCReply SetFileVersionControl(const Handle& handle, const IOCtlRequest& request);
IPCReply GetFileStats(const Handle& handle, const IOCtlRequest& request);
IPCReply GetUsage(const Handle& handle, const IOCtlVRequest& request);
IPCReply Shutdown(const Handle& handle, const IOCtlRequest& request);

u64 EstimateTicksForReadWrite(const Handle& handle, const ReadWriteRequest& request);
u64 SimulatePopulateFileCache(u32 fd, u32 offset, u32 file_size);
@@ -518,14 +518,14 @@ std::shared_ptr<Device> EmulationKernel::GetDeviceByName(std::string_view device
}

// Returns the FD for the newly opened device (on success) or an error code.
IPCCommandResult Kernel::OpenDevice(OpenRequest& request)
std::optional<IPCReply> Kernel::OpenDevice(OpenRequest& request)
{
const s32 new_fd = GetFreeDeviceID();
INFO_LOG_FMT(IOS, "Opening {} (mode {}, fd {})", request.path, request.flags, new_fd);
if (new_fd < 0 || new_fd >= IPC_MAX_FDS)
{
ERROR_LOG_FMT(IOS, "Couldn't get a free fd, too many open files");
return IPCCommandResult{IPC_EMAX, true, 5000 * SystemTimers::TIMER_RATIO};
return IPCReply{IPC_EMAX, 5000_tbticks};
}
request.fd = new_fd;

@@ -547,22 +547,22 @@ IPCCommandResult Kernel::OpenDevice(OpenRequest& request)
if (!device)
{
ERROR_LOG_FMT(IOS, "Unknown device: {}", request.path);
return {IPC_ENOENT, true, 3700 * SystemTimers::TIMER_RATIO};
return IPCReply{IPC_ENOENT, 3700_tbticks};
}

IPCCommandResult result = device->Open(request);
if (result.return_value >= IPC_SUCCESS)
std::optional<IPCReply> result = device->Open(request);
if (result && result->return_value >= IPC_SUCCESS)
{
m_fdmap[new_fd] = device;
result.return_value = new_fd;
result->return_value = new_fd;
}
return result;
}

IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
std::optional<IPCReply> Kernel::HandleIPCCommand(const Request& request)
{
if (request.command < IPC_CMD_OPEN || request.command > IPC_CMD_IOCTLV)
return IPCCommandResult{IPC_EINVAL, true, 978 * SystemTimers::TIMER_RATIO};
return IPCReply{IPC_EINVAL, 978_tbticks};

if (request.command == IPC_CMD_OPEN)
{
@@ -572,9 +572,9 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)

const auto device = (request.fd < IPC_MAX_FDS) ? m_fdmap[request.fd] : nullptr;
if (!device)
return IPCCommandResult{IPC_EINVAL, true, 550 * SystemTimers::TIMER_RATIO};
return IPCReply{IPC_EINVAL, 550_tbticks};

IPCCommandResult ret;
std::optional<IPCReply> ret;
const u64 wall_time_before = Common::Timer::GetTimeUs();

switch (request.command)
@@ -600,7 +600,7 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
break;
default:
ASSERT_MSG(IOS, false, "Unexpected command: %x", request.command);
ret = IPCCommandResult{IPC_EINVAL, true, 978 * SystemTimers::TIMER_RATIO};
ret = IPCReply{IPC_EINVAL, 978_tbticks};
break;
}

@@ -618,18 +618,18 @@ IPCCommandResult Kernel::HandleIPCCommand(const Request& request)
void Kernel::ExecuteIPCCommand(const u32 address)
{
Request request{address};
IPCCommandResult result = HandleIPCCommand(request);
std::optional<IPCReply> result = HandleIPCCommand(request);

if (!result.send_reply)
if (!result)
return;

// Ensure replies happen in order
const s64 ticks_until_last_reply = m_last_reply_time - CoreTiming::GetTicks();
if (ticks_until_last_reply > 0)
result.reply_delay_ticks += ticks_until_last_reply;
m_last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks;
result->reply_delay_ticks += ticks_until_last_reply;
m_last_reply_time = CoreTiming::GetTicks() + result->reply_delay_ticks;

EnqueueIPCReply(request, result.return_value, static_cast<int>(result.reply_delay_ticks));
EnqueueIPCReply(request, result->return_value, result->reply_delay_ticks);
}

// Happens AS SOON AS IPC gets a new pointer!
@@ -638,12 +638,11 @@ void Kernel::EnqueueIPCRequest(u32 address)
// Based on hardware tests, IOS takes between 5µs and 10µs to acknowledge an IPC request.
// Console 1: 456 TB ticks before ACK
// Console 2: 658 TB ticks before ACK
CoreTiming::ScheduleEvent(500 * SystemTimers::TIMER_RATIO, s_event_enqueue,
address | ENQUEUE_REQUEST_FLAG);
CoreTiming::ScheduleEvent(500_tbticks, s_event_enqueue, address | ENQUEUE_REQUEST_FLAG);
}

// Called to send a reply to an IOS syscall
void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, int cycles_in_future,
void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64 cycles_in_future,
CoreTiming::FromThread from)
{
Memory::Write_U32(static_cast<u32>(return_value), request.address + 4);
@@ -852,4 +851,20 @@ EmulationKernel* GetIOS()
{
return s_ios.get();
}

// Based on a hardware test, a device takes at least ~2700 ticks to reply to an IPC request.
// Depending on how much work a command performs, this can take much longer (10000+)
// especially if the NAND filesystem is accessed.
//
// Because we currently don't emulate timing very accurately, we should not return
// the minimum possible reply time (~960 ticks from the kernel or ~2700 from devices)
// but an average value, otherwise we are going to be much too fast in most cases.
IPCReply::IPCReply(s32 return_value_) : IPCReply(return_value_, 4000_tbticks)
{
}

IPCReply::IPCReply(s32 return_value_, u64 reply_delay_ticks_)
: return_value(return_value_), reply_delay_ticks(reply_delay_ticks_)
{
}
} // namespace IOS::HLE
@@ -9,6 +9,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
@@ -33,10 +34,14 @@ class ESDevice;
struct Request;
struct OpenRequest;

struct IPCCommandResult
struct IPCReply
{
/// Constructs a reply with an average reply time.
/// Please avoid using this function if more accurate timings are known.
explicit IPCReply(s32 return_value_);
explicit IPCReply(s32 return_value_, u64 reply_delay_ticks_);

s32 return_value;
bool send_reply;
u64 reply_delay_ticks;
};

@@ -84,7 +89,7 @@ class Kernel
void SDIO_EventNotify();

void EnqueueIPCRequest(u32 address);
void EnqueueIPCReply(const Request& request, s32 return_value, int cycles_in_future = 0,
void EnqueueIPCReply(const Request& request, s32 return_value, s64 cycles_in_future = 0,
CoreTiming::FromThread from = CoreTiming::FromThread::CPU);

void SetUidForPPC(u32 uid);
@@ -102,15 +107,15 @@ class Kernel
explicit Kernel(u64 title_id);

void ExecuteIPCCommand(u32 address);
IPCCommandResult HandleIPCCommand(const Request& request);
std::optional<IPCReply> HandleIPCCommand(const Request& request);
void EnqueueIPCAcknowledgement(u32 address, int cycles_in_future = 0);

void AddDevice(std::unique_ptr<Device> device);
void AddCoreDevices();
void AddStaticDevices();
std::shared_ptr<Device> GetDeviceByName(std::string_view device_name);
s32 GetFreeDeviceID();
IPCCommandResult OpenDevice(OpenRequest& request);
std::optional<IPCReply> OpenDevice(OpenRequest& request);

bool m_is_responsible_for_nand_root = false;
u64 m_title_id = 0;