From 58624ef409d640416ffce902865372445a564261 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 5 Aug 2017 03:19:20 +0200 Subject: [PATCH 01/14] ES: Fix wrong log message. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index c35eeec0e9..cf60c31bb6 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -101,7 +101,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) constexpr u32 MAX_TMD_SIZE = 0x4000; if (tmd_size > MAX_TMD_SIZE) { - ERROR_LOG(IOS, "IOCTL_WFSI_INIT: TMD size too large (%d)", tmd_size); + ERROR_LOG(IOS, "IOCTL_WFSI_PREPARE_DEVICE: TMD size too large (%d)", tmd_size); return_error_code = IPC_EINVAL; break; } From 385f063be1a865919fbcb7180a63f1ef8c595584 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 5 Aug 2017 03:19:50 +0200 Subject: [PATCH 02/14] ES: Split out GetTitleId to a separate method. --- Source/Core/Core/IOS/ES/ES.cpp | 19 ++++++++++++++----- Source/Core/Core/IOS/ES/ES.h | 3 ++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index edcb89dca8..e398d0bb5c 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -165,15 +165,24 @@ IPCCommandResult ES::GetTitleDirectory(const IOCtlVRequest& request) return GetDefaultReply(IPC_SUCCESS); } -IPCCommandResult ES::GetTitleID(const IOCtlVRequest& request) +ReturnCode ES::GetTitleId(u64* title_id) const +{ + if (!s_title_context.active) + return ES_EINVAL; + *title_id = s_title_context.tmd.GetTitleId(); + return IPC_SUCCESS; +} + +IPCCommandResult ES::GetTitleId(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(0, 1)) return GetDefaultReply(ES_EINVAL); - if (!s_title_context.active) - return GetDefaultReply(ES_EINVAL); + u64 title_id; + const ReturnCode ret = GetTitleId(&title_id); + if (ret != IPC_SUCCESS) + return GetDefaultReply(ret); - const u64 title_id = s_title_context.tmd.GetTitleId(); Memory::Write_U64(title_id, request.io_vectors[0].address); INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", static_cast(title_id >> 32), static_cast(title_id)); @@ -421,7 +430,7 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) case IOCTL_ES_GETTITLEDIR: return GetTitleDirectory(request); case IOCTL_ES_GETTITLEID: - return GetTitleID(request); + return GetTitleId(request); case IOCTL_ES_SETUID: return SetUID(context->uid, request); case IOCTL_ES_DIVERIFY: diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 6352eec917..b21c3335d1 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -127,6 +127,7 @@ public: ReturnCode DeleteContent(u64 title_id, u32 content_id) const; ReturnCode GetDeviceId(u32* device_id) const; + ReturnCode GetTitleId(u64* device_id) const; // Views ReturnCode GetV0TicketFromView(const u8* ticket_view, u8* ticket) const; @@ -243,7 +244,7 @@ private: // Misc IPCCommandResult SetUID(u32 uid, const IOCtlVRequest& request); IPCCommandResult GetTitleDirectory(const IOCtlVRequest& request); - IPCCommandResult GetTitleID(const IOCtlVRequest& request); + IPCCommandResult GetTitleId(const IOCtlVRequest& request); IPCCommandResult GetConsumption(const IOCtlVRequest& request); IPCCommandResult Launch(const IOCtlVRequest& request); IPCCommandResult LaunchBC(const IOCtlVRequest& request); From f0ba0f617f9d09023bc3596076fc094d4249f24a Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 5 Aug 2017 03:24:00 +0200 Subject: [PATCH 03/14] WFS: Fix shutdown behavior with long hanging requests. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 53 ++++++++++++++++++++++++++++- Source/Core/Core/IOS/WFS/WFSI.h | 8 +++++ Source/Core/Core/IOS/WFS/WFSSRV.cpp | 20 +++++++++-- Source/Core/Core/IOS/WFS/WFSSRV.h | 6 ++++ 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index cf60c31bb6..6eae92bf72 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -15,6 +15,7 @@ #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Core/HW/Memmap.h" +#include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/Formats.h" #include "Core/IOS/WFS/WFSSRV.h" #include "DiscIO/NANDContentLoader.h" @@ -215,8 +216,13 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; case IOCTL_WFSI_INIT: - // Nothing to do. INFO_LOG(IOS, "IOCTL_WFSI_INIT"); + if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0) + { + ERROR_LOG(IOS, "IOCTL_WFSI_INIT: Could not get title id."); + return_error_code = IPC_EINVAL; + break; + } break; case IOCTL_WFSI_SET_DEVICE_NAME: @@ -235,6 +241,51 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; + case IOCTL_WFSI_LOAD_DOL: + { + std::string path = StringFromFormat( + "/vol/%s/_install/%c%c%c%c/content", m_device_name.c_str(), + static_cast(m_title_id >> 24), static_cast(m_title_id >> 16), + static_cast(m_title_id >> 8), static_cast(m_title_id)); + + u32 dol_addr = Memory::Read_U32(request.buffer_in + 0x18); + u32 max_dol_size = Memory::Read_U32(request.buffer_in + 0x14); + u16 dol_extension_id = Memory::Read_U16(request.buffer_in + 0x1e); + + if (dol_extension_id == 0) + { + path += "/default.dol"; + } + else + { + path += StringFromFormat("/extension%d.dol", dol_extension_id); + } + + INFO_LOG(IOS, "IOCTL_WFSI_LOAD_DOL: loading %s at address %08x (size %d)", path.c_str(), + dol_addr, max_dol_size); + + File::IOFile fp(WFS::NativePath(path), "rb"); + if (!fp) + { + WARN_LOG(IOS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str()); + return_error_code = WFSI_ENOENT; + break; + } + + u32 real_dol_size = fp.GetSize(); + if (dol_addr == 0) + { + // Write the expected size to the size parameter, in the input. + Memory::Write_U32(real_dol_size, request.buffer_in + 0x14); + } + else + { + fp.ReadBytes(Memory::GetPointer(dol_addr), max_dol_size); + } + Memory::Write_U32(real_dol_size, request.buffer_out); + break; + } + default: // TODO(wfs): Should be returning an error. However until we have // everything properly stubbed it's easier to simulate the methods diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index a6494c4f2c..77e4a827f6 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -52,9 +52,15 @@ private: IOS::ES::TMDReader m_tmd; std::string m_base_extract_path; + u64 m_title_id; ARCUnpacker m_arc_unpacker; + enum + { + WFSI_ENOENT = -12000, + }; + enum { IOCTL_WFSI_PREPARE_DEVICE = 0x02, @@ -74,6 +80,8 @@ private: IOCTL_WFSI_FINALIZE_PROFILE = 0x88, IOCTL_WFSI_APPLY_TITLE_PROFILE = 0x89, + + IOCTL_WFSI_LOAD_DOL = 0x90, }; }; } // namespace Device diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 81639e69ad..2251b28161 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -44,6 +44,20 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS, "IOCTL_WFS_INIT"); break; + case IOCTL_WFS_SHUTDOWN: + INFO_LOG(IOS, "IOCTL_WFS_SHUTDOWN"); + + // Close all hanging attach/detach ioctls with an appropriate error code. + for (auto address : m_hanging) + { + IOCtlRequest hanging_request{address}; + Memory::Write_U32(0x80000000, hanging_request.buffer_out); + Memory::Write_U32(0, hanging_request.buffer_out + 4); + Memory::Write_U32(0, hanging_request.buffer_out + 8); + m_ios.EnqueueIPCReply(hanging_request, 0); + } + break; + case IOCTL_WFS_DEVICE_INFO: INFO_LOG(IOS, "IOCTL_WFS_DEVICE_INFO"); Memory::Write_U64(16ull << 30, request.buffer_out); // 16GB storage. @@ -68,9 +82,9 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) case IOCTL_WFS_ATTACH_DETACH: INFO_LOG(IOS, "IOCTL_WFS_ATTACH_DETACH(%u)", request.request); - Memory::Write_U32(1, request.buffer_out); - Memory::Write_U32(0, request.buffer_out + 4); - Memory::Write_U32(0, request.buffer_out + 8); + + // Leave hanging, but we need to acknowledge the request at shutdown time. + m_hanging.push_back(request.address); return GetNoReply(); // TODO(wfs): Globbing is not really implemented, we just fake the one case diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 602d30777e..0741bc1922 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -38,8 +38,10 @@ private: enum { IOCTL_WFS_INIT = 0x02, + IOCTL_WFS_SHUTDOWN = 0x03, IOCTL_WFS_DEVICE_INFO = 0x04, IOCTL_WFS_GET_DEVICE_NAME = 0x05, + IOCTL_WFS_UNMOUNT_VOLUME = 0x06, IOCTL_WFS_FLUSH = 0x0a, IOCTL_WFS_GLOB_START = 0x0d, IOCTL_WFS_GLOB_NEXT = 0x0e, @@ -75,6 +77,10 @@ private: }; std::vector m_fds; + // List of addresses of IPC requests left hanging that need closing at + // shutdown time. + std::vector m_hanging; + FileDescriptor* FindFileDescriptor(u16 fd); u16 GetNewFileDescriptor(); void ReleaseFileDescriptor(u16 fd); From f3224dc726c9362b01629c1da7bc209361a6335e Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 5 Aug 2017 16:50:50 +0200 Subject: [PATCH 04/14] WFS: Stub out unimplemented ioctl 0x08. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 7 +++++++ Source/Core/Core/IOS/WFS/WFSSRV.h | 1 + 2 files changed, 8 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 2251b28161..d04885f985 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -44,6 +44,13 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS, "IOCTL_WFS_INIT"); break; + case IOCTL_WFS_UNKNOWN_8: + // TODO(wfs): Figure out what this actually does. + INFO_LOG(IOS, "IOCTL_WFS_UNKNOWN_8"); + Memory::Write_U8(7, request.buffer_out); + Memory::CopyToEmu(request.buffer_out + 1, "msc01\x00\x00\x00", 8); + break; + case IOCTL_WFS_SHUTDOWN: INFO_LOG(IOS, "IOCTL_WFS_SHUTDOWN"); diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 0741bc1922..0f4de83e3f 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -42,6 +42,7 @@ private: IOCTL_WFS_DEVICE_INFO = 0x04, IOCTL_WFS_GET_DEVICE_NAME = 0x05, IOCTL_WFS_UNMOUNT_VOLUME = 0x06, + IOCTL_WFS_UNKNOWN_8 = 0x08, IOCTL_WFS_FLUSH = 0x0a, IOCTL_WFS_GLOB_START = 0x0d, IOCTL_WFS_GLOB_NEXT = 0x0e, From 5a4900bc96750a6e30f5b513bb03f981bd32e4db Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 5 Aug 2017 19:51:06 +0200 Subject: [PATCH 05/14] WFS: Stub WFSSRV's flush command. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index d04885f985..5a01916d55 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -94,6 +94,11 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) m_hanging.push_back(request.address); return GetNoReply(); + case IOCTL_WFS_FLUSH: + // Nothing to do. + INFO_LOG(IOS, "IOCTL_WFS_FLUSH: doing nothing"); + break; + // TODO(wfs): Globbing is not really implemented, we just fake the one case // (listing /vol/*) which is required to get the installer to work. case IOCTL_WFS_GLOB_START: From c14ab0dd539f552e652d842326e4e8918827ea2e Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 5 Aug 2017 19:51:29 +0200 Subject: [PATCH 06/14] WFS: Implement current/home path expansion. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 32 +++++++++++++++++++++++++++++ Source/Core/Core/IOS/WFS/WFSSRV.h | 14 +++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 5a01916d55..1f82768ad4 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -117,12 +117,26 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) Memory::Memset(request.buffer_out, 0, request.buffer_out_size); break; + case IOCTL_WFS_SET_HOMEDIR: + m_home_directory = + Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in)); + INFO_LOG(IOS, "IOCTL_WFS_SET_HOMEDIR: %s", m_home_directory.c_str()); + break; + + case IOCTL_WFS_CHDIR: + m_current_directory = + Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in)); + INFO_LOG(IOS, "IOCTL_WFS_CHDIR: %s", m_current_directory.c_str()); + break; + case IOCTL_WFS_OPEN: { u32 mode = Memory::Read_U32(request.buffer_in); u16 path_len = Memory::Read_U16(request.buffer_in + 0x20); std::string path = Memory::GetString(request.buffer_in + 0x22, path_len); + path = ExpandPath(path); + u16 fd = GetNewFileDescriptor(); FileDescriptor* fd_obj = &m_fds[fd]; fd_obj->in_use = true; @@ -190,6 +204,24 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) return GetDefaultReply(return_error_code); } +std::string WFSSRV::ExpandPath(const std::string& path) const +{ + std::string expanded; + if (!path.empty() && path[0] == '~') + { + expanded = m_home_directory + "/" + path.substr(1); + } + else if (path.empty() || path[0] != '/') + { + expanded = m_current_directory + "/" + path; + } + else + { + expanded = path; + } + return expanded; +} + WFSSRV::FileDescriptor* WFSSRV::FindFileDescriptor(u16 fd) { if (fd >= m_fds.size() || !m_fds[fd].in_use) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 0f4de83e3f..72432ae754 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -35,6 +35,12 @@ private: // WFS device name, e.g. msc01/msc02. std::string m_device_name; + // Home / current directories. + std::string m_home_directory; + std::string m_current_directory; + + std::string ExpandPath(const std::string& path) const; + enum { IOCTL_WFS_INIT = 0x02, @@ -78,13 +84,13 @@ private: }; std::vector m_fds; - // List of addresses of IPC requests left hanging that need closing at - // shutdown time. - std::vector m_hanging; - FileDescriptor* FindFileDescriptor(u16 fd); u16 GetNewFileDescriptor(); void ReleaseFileDescriptor(u16 fd); + + // List of addresses of IPC requests left hanging that need closing at + // shutdown time. + std::vector m_hanging; }; } // namespace Device } // namespace HLE From f8e5f4296f7f6be16a46fbd1f27031c85ed0a13b Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 5 Aug 2017 19:51:42 +0200 Subject: [PATCH 07/14] WFS: Document WFSSRV ioctl 0x0c as being mkdir. --- Source/Core/Core/IOS/WFS/WFSSRV.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 72432ae754..86302a80bb 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -50,6 +50,7 @@ private: IOCTL_WFS_UNMOUNT_VOLUME = 0x06, IOCTL_WFS_UNKNOWN_8 = 0x08, IOCTL_WFS_FLUSH = 0x0a, + IOCTL_WFS_MKDIR = 0x0c, IOCTL_WFS_GLOB_START = 0x0d, IOCTL_WFS_GLOB_NEXT = 0x0e, IOCTL_WFS_GLOB_END = 0x0f, From f810f1edb2830fa7dbaccae94b51b0f39e8726c6 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sun, 6 Aug 2017 17:11:25 +0200 Subject: [PATCH 08/14] WFS/NAND: Better handle GID. --- Source/Core/Common/NandPaths.cpp | 29 +++++++++++++++++++++++++++++ Source/Core/Common/NandPaths.h | 3 +++ Source/Core/Core/IOS/FS/FS.cpp | 14 ++++++++++++++ Source/Core/Core/IOS/WFS/WFSI.cpp | 21 +++++++++++++-------- Source/Core/Core/IOS/WFS/WFSI.h | 3 +++ 5 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Source/Core/Common/NandPaths.cpp b/Source/Core/Common/NandPaths.cpp index 1fcbab38be..ec43b38484 100644 --- a/Source/Core/Common/NandPaths.cpp +++ b/Source/Core/Common/NandPaths.cpp @@ -58,6 +58,35 @@ std::string GetTMDFileName(u64 _titleID, FromWhichRoot from) return GetTitleContentPath(_titleID, from) + "title.tmd"; } +bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id) +{ + std::string expected_prefix = RootUserPath(from) + "/title/"; + if (!StringBeginsWith(path, expected_prefix)) + { + return false; + } + + // Try to find a title ID in the remaining path. + std::string subdirectory = path.substr(expected_prefix.size()); + std::vector components = SplitString(subdirectory, '/'); + if (components.size() < 2) + { + return false; + } + + u32 title_id_high, title_id_low; + if (!AsciiToHex(components[0], title_id_high) || !AsciiToHex(components[1], title_id_low)) + { + return false; + } + + if (title_id != nullptr) + { + *title_id = (static_cast(title_id_high) << 32) | title_id_low; + } + return true; +} + std::string EscapeFileName(const std::string& filename) { // Prevent paths from containing special names like ., .., ..., ...., and so on diff --git a/Source/Core/Common/NandPaths.h b/Source/Core/Common/NandPaths.h index 0a7738664c..6ef53a9912 100644 --- a/Source/Core/Common/NandPaths.h +++ b/Source/Core/Common/NandPaths.h @@ -29,6 +29,9 @@ std::string GetTitleDataPath(u64 _titleID, FromWhichRoot from); std::string GetTitleContentPath(u64 _titleID, FromWhichRoot from); std::string GetTMDFileName(u64 _titleID, FromWhichRoot from); +// Returns whether a path is within an installed title's directory. +bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id = nullptr); + // Escapes characters that are invalid or have special meanings in the host file system std::string EscapeFileName(const std::string& filename); // Escapes characters that are invalid or have special meanings in the host file system diff --git a/Source/Core/Core/IOS/FS/FS.cpp b/Source/Core/Core/IOS/FS/FS.cpp index 3ebad9c46a..50e8a47b28 100644 --- a/Source/Core/Core/IOS/FS/FS.cpp +++ b/Source/Core/Core/IOS/FS/FS.cpp @@ -21,6 +21,8 @@ #include "Common/NandPaths.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/IOS/ES/ES.h" +#include "Core/IOS/ES/Formats.h" #include "Core/IOS/FS/FileIO.h" namespace IOS @@ -326,6 +328,18 @@ IPCCommandResult FS::GetAttribute(const IOCtlRequest& request) u8 OtherPerm = 0x3; // read/write u8 Attributes = 0x00; // no attributes + // Hack: if the path that is being accessed is within an installed title directory, get the + // UID/GID from the installed title TMD. + u64 title_id; + if (IsTitlePath(Filename, Common::FROM_SESSION_ROOT, &title_id)) + { + IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(title_id); + if (tmd.IsValid()) + { + GroupID = tmd.GetGroupId(); + } + } + if (File::IsDirectory(Filename)) { INFO_LOG(IOS_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set", diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 6eae92bf72..9059269308 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -216,6 +216,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; case IOCTL_WFSI_INIT: + { INFO_LOG(IOS, "IOCTL_WFSI_INIT"); if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0) { @@ -223,7 +224,15 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) return_error_code = IPC_EINVAL; break; } + m_title_id_str = StringFromFormat( + "%c%c%c%c", static_cast(m_title_id >> 24), static_cast(m_title_id >> 16), + static_cast(m_title_id >> 8), static_cast(m_title_id)); + + IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(m_title_id); + m_group_id = tmd.GetGroupId(); + m_group_id_str = StringFromFormat("%c%c", m_group_id >> 8, m_group_id & 0xFF); break; + } case IOCTL_WFSI_SET_DEVICE_NAME: INFO_LOG(IOS, "IOCTL_WFSI_SET_DEVICE_NAME"); @@ -233,20 +242,16 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_APPLY_TITLE_PROFILE: INFO_LOG(IOS, "IOCTL_WFSI_APPLY_TITLE_PROFILE"); - m_base_extract_path = StringFromFormat( - "/vol/%s/_install/%c%c%c%c/content", m_device_name.c_str(), - static_cast(m_tmd.GetTitleId() >> 24), static_cast(m_tmd.GetTitleId() >> 16), - static_cast(m_tmd.GetTitleId() >> 8), static_cast(m_tmd.GetTitleId())); + m_base_extract_path = StringFromFormat("/vol/%s/_install/%s/content", m_device_name.c_str(), + m_title_id_str.c_str()); File::CreateFullPath(WFS::NativePath(m_base_extract_path)); break; case IOCTL_WFSI_LOAD_DOL: { - std::string path = StringFromFormat( - "/vol/%s/_install/%c%c%c%c/content", m_device_name.c_str(), - static_cast(m_title_id >> 24), static_cast(m_title_id >> 16), - static_cast(m_title_id >> 8), static_cast(m_title_id)); + std::string path = StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), + m_group_id_str.c_str(), m_title_id_str.c_str()); u32 dol_addr = Memory::Read_U32(request.buffer_in + 0x18); u32 max_dol_size = Memory::Read_U32(request.buffer_in + 0x14); diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 77e4a827f6..5ed9ee21eb 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -53,6 +53,9 @@ private: IOS::ES::TMDReader m_tmd; std::string m_base_extract_path; u64 m_title_id; + std::string m_title_id_str; + u16 m_group_id; + std::string m_group_id_str; ARCUnpacker m_arc_unpacker; From 425cf18bf7973a5b23607bf7827421f28911c584 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sun, 6 Aug 2017 22:17:51 +0200 Subject: [PATCH 09/14] USB: Add a stub HIDv5 implementation and use it for IOS59. --- Source/Core/Core/CMakeLists.txt | 1 + Source/Core/Core/Core.vcxproj | 2 + Source/Core/Core/Core.vcxproj.filters | 6 +++ Source/Core/Core/IOS/IOS.cpp | 6 ++- Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp | 63 ++++++++++++++++++++++ Source/Core/Core/IOS/USB/USB_HID/HIDv5.h | 37 +++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp create mode 100644 Source/Core/Core/IOS/USB/USB_HID/HIDv5.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 04dbcf5848..9fd579888b 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -186,6 +186,7 @@ set(SRCS IOS/USB/OH0/OH0.cpp IOS/USB/OH0/OH0Device.cpp IOS/USB/USB_HID/HIDv4.cpp + IOS/USB/USB_HID/HIDv5.cpp IOS/USB/USB_VEN/VEN.cpp IOS/USB/USBV0.cpp IOS/USB/USBV4.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 8968495f03..5e275711de 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -221,6 +221,7 @@ + @@ -468,6 +469,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 0f5eff13f5..167fcec007 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -826,6 +826,9 @@ IOS\USB + + IOS\USB + IOS\USB @@ -1469,6 +1472,9 @@ IOS\USB + + IOS\USB + IOS\USB diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 06c8e4ecd1..3d372c7688 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -47,6 +47,7 @@ #include "Core/IOS/USB/OH0/OH0.h" #include "Core/IOS/USB/OH0/OH0Device.h" #include "Core/IOS/USB/USB_HID/HIDv4.h" +#include "Core/IOS/USB/USB_HID/HIDv5.h" #include "Core/IOS/USB/USB_KBD.h" #include "Core/IOS/USB/USB_VEN/VEN.h" #include "Core/IOS/WFS/WFSI.h" @@ -361,7 +362,10 @@ void Kernel::AddStaticDevices() AddDevice(std::make_unique(*this, "/dev/usb/kbd")); AddDevice(std::make_unique(*this, "/dev/sdio/slot0")); AddDevice(std::make_unique(*this, "/dev/sdio/slot1")); - AddDevice(std::make_unique(*this, "/dev/usb/hid")); + if (GetVersion() == 59) + AddDevice(std::make_unique(*this, "/dev/usb/hid")); + else + AddDevice(std::make_unique(*this, "/dev/usb/hid")); AddDevice(std::make_unique(*this, "/dev/usb/oh0")); AddDevice(std::make_unique(*this, "/dev/usb/oh1")); AddDevice(std::make_unique(*this, "/dev/usb/ven")); diff --git a/Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp new file mode 100644 index 0000000000..d51d648c66 --- /dev/null +++ b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp @@ -0,0 +1,63 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/IOS/USB/USB_HID/HIDv5.h" + +#include + +#include "Core/HW/Memmap.h" +#include "Core/IOS/Device.h" +#include "Core/IOS/USB/Common.h" +#include "Core/IOS/USB/USBV5.h" + +namespace IOS +{ +namespace HLE +{ +namespace Device +{ +USB_HIDv5::USB_HIDv5(Kernel& ios, const std::string& device_name) : USBHost(ios, device_name) +{ +} + +USB_HIDv5::~USB_HIDv5() +{ + StopThreads(); +} + +IPCCommandResult USB_HIDv5::IOCtl(const IOCtlRequest& request) +{ + request.Log(GetDeviceName(), LogTypes::IOS_USB); + switch (request.request) + { + case USB::IOCTL_USBV5_GETVERSION: + Memory::Write_U32(VERSION, request.buffer_out); + return GetDefaultReply(IPC_SUCCESS); + case USB::IOCTL_USBV5_SHUTDOWN: + if (m_hanging_request) + { + IOCtlRequest hanging_request{m_hanging_request}; + m_ios.EnqueueIPCReply(hanging_request, IPC_SUCCESS); + } + return GetDefaultReply(IPC_SUCCESS); + case USB::IOCTL_USBV5_GETDEVICECHANGE: + if (m_devicechange_replied) + { + m_hanging_request = request.address; + return GetNoReply(); + } + else + { + m_devicechange_replied = true; + return GetDefaultReply(IPC_SUCCESS); + } + default: + request.DumpUnknown(GetDeviceName(), LogTypes::IOS_USB); + return GetDefaultReply(IPC_SUCCESS); + } +} + +} // namespace Device +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USB_HID/HIDv5.h b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.h new file mode 100644 index 0000000000..069651ff6e --- /dev/null +++ b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.h @@ -0,0 +1,37 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "Common/CommonTypes.h" +#include "Core/IOS/IOS.h" +#include "Core/IOS/USB/Host.h" + +namespace IOS +{ +namespace HLE +{ +namespace Device +{ +// Stub implementation that only gets DQX to boot. +class USB_HIDv5 : public USBHost +{ +public: + USB_HIDv5(Kernel& ios, const std::string& device_name); + ~USB_HIDv5() override; + + IPCCommandResult IOCtl(const IOCtlRequest& request) override; + +private: + static constexpr u32 VERSION = 0x50001; + + u32 m_hanging_request = 0; + bool m_devicechange_replied = false; +}; + +} // namespace Device +} // namespace HLE +} // namespace IOS From 2f5ddf12a9058cef80f17a1fc3635fc2b3f46c18 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sun, 6 Aug 2017 22:18:20 +0200 Subject: [PATCH 10/14] WFS: Normalize paths before opening. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 24 +++++++++++++++++++++--- Source/Core/Core/IOS/WFS/WFSSRV.h | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 1f82768ad4..6ff55a8e66 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -135,7 +135,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) u16 path_len = Memory::Read_U16(request.buffer_in + 0x20); std::string path = Memory::GetString(request.buffer_in + 0x22, path_len); - path = ExpandPath(path); + path = NormalizePath(path); u16 fd = GetNewFileDescriptor(); FileDescriptor* fd_obj = &m_fds[fd]; @@ -204,7 +204,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) return GetDefaultReply(return_error_code); } -std::string WFSSRV::ExpandPath(const std::string& path) const +std::string WFSSRV::NormalizePath(const std::string& path) const { std::string expanded; if (!path.empty() && path[0] == '~') @@ -219,7 +219,25 @@ std::string WFSSRV::ExpandPath(const std::string& path) const { expanded = path; } - return expanded; + + std::vector components = SplitString(expanded, '/'); + std::vector normalized_components; + for (const auto& component : components) + { + if (component.empty() || component == ".") + { + continue; + } + else if (component == ".." && !normalized_components.empty()) + { + normalized_components.pop_back(); + } + else + { + normalized_components.push_back(component); + } + } + return "/" + JoinStrings(normalized_components, "/"); } WFSSRV::FileDescriptor* WFSSRV::FindFileDescriptor(u16 fd) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 86302a80bb..889bfc25fd 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -39,7 +39,7 @@ private: std::string m_home_directory; std::string m_current_directory; - std::string ExpandPath(const std::string& path) const; + std::string NormalizePath(const std::string& path) const; enum { From 49a4712f33f9362c0ee92d23ecc3454afa5e1f62 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sun, 6 Aug 2017 22:18:48 +0200 Subject: [PATCH 11/14] WFS: Implemented the GET_SIZE ioctl. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 23 +++++++++++++++++++++++ Source/Core/Core/IOS/WFS/WFSSRV.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 6ff55a8e66..a2601f3422 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -4,6 +4,7 @@ #include "Core/IOS/WFS/WFSSRV.h" +#include #include #include @@ -157,6 +158,28 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFS_GET_SIZE: + { + u16 fd = Memory::Read_U16(request.buffer_in); + FileDescriptor* fd_obj = FindFileDescriptor(fd); + if (fd_obj == nullptr) + { + ERROR_LOG(IOS, "IOCTL_WFS_GET_SIZE: invalid file descriptor %d", fd); + return_error_code = WFS_EBADFD; + break; + } + + u64 size = fd_obj->file.GetSize(); + u32 truncated_size = static_cast(size); + INFO_LOG(IOS, "IOCTL_WFS_GET_SIZE(%d) -> %d", fd, truncated_size); + if (size != truncated_size) + { + ERROR_LOG(IOS, "IOCTL_WFS_GET_SIZE: file %d too large (%" PRIu64 ")", fd, size); + } + Memory::Write_U32(truncated_size, request.buffer_out); + break; + } + case IOCTL_WFS_CLOSE: { u16 fd = Memory::Read_U16(request.buffer_in + 0x4); diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 889bfc25fd..72b051f87a 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -61,6 +61,7 @@ private: IOCTL_WFS_DELETE = 0x15, IOCTL_WFS_GET_ATTRIBUTES = 0x17, IOCTL_WFS_OPEN = 0x1A, + IOCTL_WFS_GET_SIZE = 0x1B, IOCTL_WFS_CLOSE = 0x1E, IOCTL_WFS_READ = 0x20, IOCTL_WFS_WRITE = 0x22, @@ -70,6 +71,7 @@ private: enum { + WFS_EBADFD = -10026, // Invalid file descriptor. WFS_EEMPTY = -10028, // Directory is empty of iteration completed. }; From 397f5e54e0472b0f2e348dcdb648adfbeef8ba3a Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sun, 6 Aug 2017 22:19:08 +0200 Subject: [PATCH 12/14] WFS: Implement READ_ABSOLUTE (merged with READ implementation). --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 25 +++++++++++++++++++------ Source/Core/Core/IOS/WFS/WFSSRV.h | 1 + 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index a2601f3422..0a76d6e482 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -189,26 +189,39 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) } case IOCTL_WFS_READ: + case IOCTL_WFS_READ_ABSOLUTE: { u32 addr = Memory::Read_U32(request.buffer_in); + u32 position = Memory::Read_U32(request.buffer_in + 4); // Only for absolute. u16 fd = Memory::Read_U16(request.buffer_in + 0xC); u32 size = Memory::Read_U32(request.buffer_in + 8); + bool absolute = request.request == IOCTL_WFS_READ_ABSOLUTE; + FileDescriptor* fd_obj = FindFileDescriptor(fd); if (fd_obj == nullptr) { ERROR_LOG(IOS, "IOCTL_WFS_READ: invalid file descriptor %d", fd); - return_error_code = -1; // TODO(wfs): proper error code. + return_error_code = WFS_EBADFD; break; } - size_t read_bytes; - if (!fd_obj->file.ReadArray(Memory::GetPointer(addr), size, &read_bytes)) + u64 previous_position = fd_obj->file.Tell(); + if (absolute) { - return_error_code = -1; // TODO(wfs): proper error code. - break; + fd_obj->file.Seek(position, SEEK_SET); + } + size_t read_bytes; + fd_obj->file.ReadArray(Memory::GetPointer(addr), size, &read_bytes); + // TODO(wfs): Handle read errors. + if (absolute) + { + fd_obj->file.Seek(previous_position, SEEK_SET); + } + else + { + fd_obj->position += read_bytes; } - fd_obj->position += read_bytes; INFO_LOG(IOS, "IOCTL_WFS_READ: read %zd bytes from FD %d (%s)", read_bytes, fd, fd_obj->path.c_str()); diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 72b051f87a..cba30037a1 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -67,6 +67,7 @@ private: IOCTL_WFS_WRITE = 0x22, IOCTL_WFS_ATTACH_DETACH = 0x2d, IOCTL_WFS_ATTACH_DETACH_2 = 0x2e, + IOCTL_WFS_READ_ABSOLUTE = 0x48, }; enum From 1e75455ef5e64d3d8ec5c9eec7a6cd800e7417c0 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Mon, 7 Aug 2017 02:09:31 +0200 Subject: [PATCH 13/14] WFS: Return a proper ENOENT code on failed OPEN. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 4 ++-- Source/Core/Core/IOS/WFS/WFSSRV.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 0a76d6e482..7d3e6af3da 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -110,7 +110,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) case IOCTL_WFS_GLOB_NEXT: INFO_LOG(IOS, "IOCTL_WFS_GLOB_NEXT(%u)", request.request); - return_error_code = WFS_EEMPTY; + return_error_code = WFS_ENOENT; break; case IOCTL_WFS_GLOB_END: @@ -149,7 +149,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) { ERROR_LOG(IOS, "IOCTL_WFS_OPEN(%s, %d): error opening file", path.c_str(), mode); ReleaseFileDescriptor(fd); - return_error_code = -1; // TODO(wfs): proper error code. + return_error_code = WFS_ENOENT; break; } diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index cba30037a1..f509ae9ee1 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -73,7 +73,7 @@ private: enum { WFS_EBADFD = -10026, // Invalid file descriptor. - WFS_EEMPTY = -10028, // Directory is empty of iteration completed. + WFS_ENOENT = -10028, // No such file or directory. }; struct FileDescriptor From 40c70469e5cf20124e49f8c41827173e87cbda3f Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Mon, 7 Aug 2017 17:18:46 +0200 Subject: [PATCH 14/14] WFS: Implement GET_HOMEDIR. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 7d3e6af3da..b714a821a6 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -130,6 +130,12 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS, "IOCTL_WFS_CHDIR: %s", m_current_directory.c_str()); break; + case IOCTL_WFS_GET_HOMEDIR: + INFO_LOG(IOS, "IOCTL_WFS_GET_HOMEDIR: %s", m_home_directory.c_str()); + Memory::Write_U16(static_cast(m_home_directory.size()), request.buffer_out); + Memory::CopyToEmu(request.buffer_out + 2, m_home_directory.data(), m_home_directory.size()); + break; + case IOCTL_WFS_OPEN: { u32 mode = Memory::Read_U32(request.buffer_in);