diff options
Diffstat (limited to 'src/core/hle/service')
28 files changed, 333 insertions, 98 deletions
diff --git a/src/core/hle/service/act/act.cpp b/src/core/hle/service/act/act.cpp new file mode 100644 index 000000000..9600036c0 --- /dev/null +++ b/src/core/hle/service/act/act.cpp @@ -0,0 +1,18 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/act/act.h" +#include "core/hle/service/act/act_a.h" +#include "core/hle/service/act/act_u.h" + +namespace Service { +namespace ACT { + +void Init() { + AddService(new ACT_A); + AddService(new ACT_U); +} + +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h new file mode 100644 index 000000000..1425291aa --- /dev/null +++ b/src/core/hle/service/act/act.h @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service { +namespace ACT { + +/// Initializes all ACT services +void Init(); + +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act_a.cpp b/src/core/hle/service/act/act_a.cpp index 9880aafff..5c523368f 100644 --- a/src/core/hle/service/act_a.cpp +++ b/src/core/hle/service/act/act_a.cpp @@ -2,7 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/service/act_a.h" +#include "core/hle/service/act/act.h" +#include "core/hle/service/act/act_a.h" namespace Service { namespace ACT { diff --git a/src/core/hle/service/act_a.h b/src/core/hle/service/act/act_a.h index e3adb03e5..e3adb03e5 100644 --- a/src/core/hle/service/act_a.h +++ b/src/core/hle/service/act/act_a.h diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act/act_u.cpp index b4f69c57d..cf98aa1d6 100644 --- a/src/core/hle/service/act_u.cpp +++ b/src/core/hle/service/act/act_u.cpp @@ -2,7 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/service/act_u.h" +#include "core/hle/service/act/act.h" +#include "core/hle/service/act/act_u.h" namespace Service { namespace ACT { diff --git a/src/core/hle/service/act_u.h b/src/core/hle/service/act/act_u.h index 9d8538fbf..9d8538fbf 100644 --- a/src/core/hle/service/act_u.h +++ b/src/core/hle/service/act/act_u.h diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index e6a8be870..80325361f 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -14,6 +14,9 @@ class Interface; namespace APT { +/// Each APT service can only have up to 2 sessions connected at the same time. +static const u32 MaxAPTSessions = 2; + /// Holds information about the parameters used in Send/Glance/ReceiveParameter struct MessageParameter { u32 sender_id = 0; diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index 6e35e1d29..62dc2d61d 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -102,7 +102,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x01050100, nullptr, "IsTitleAllowed"}, }; -APT_A_Interface::APT_A_Interface() { +APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 84019e6e5..effd23dce 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -102,7 +102,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x01050100, nullptr, "IsTitleAllowed"}, }; -APT_S_Interface::APT_S_Interface() { +APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index a731c39f6..e06084a1e 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x01020000, CheckNew3DS, "CheckNew3DS"}, }; -APT_U_Interface::APT_U_Interface() { +APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 515b344e6..eb04273db 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -5,6 +5,7 @@ #include "common/logging/log.h" #include "core/hle/kernel/event.h" #include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_ndm.h" #include "core/hle/service/cecd/cecd_s.h" #include "core/hle/service/cecd/cecd_u.h" #include "core/hle/service/service.h" @@ -43,12 +44,13 @@ void GetChangeStateEventHandle(Service::Interface* self) { } void Init() { - AddService(new CECD_S_Interface); - AddService(new CECD_U_Interface); + AddService(new CECD_NDM); + AddService(new CECD_S); + AddService(new CECD_U); - cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::cecinfo_event"); + cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::cecinfo_event"); change_state_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::change_state_event"); + Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::change_state_event"); } void Shutdown() { diff --git a/src/core/hle/service/cecd/cecd_ndm.cpp b/src/core/hle/service/cecd/cecd_ndm.cpp new file mode 100644 index 000000000..7baf93750 --- /dev/null +++ b/src/core/hle/service/cecd/cecd_ndm.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_ndm.h" + +namespace Service { +namespace CECD { + +static const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "Initialize"}, + {0x00020000, nullptr, "Deinitialize"}, + {0x00030000, nullptr, "ResumeDaemon"}, + {0x00040040, nullptr, "SuspendDaemon"}, +}; + +CECD_NDM::CECD_NDM() { + Register(FunctionTable); +} + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_ndm.h b/src/core/hle/service/cecd/cecd_ndm.h new file mode 100644 index 000000000..2e2e50ada --- /dev/null +++ b/src/core/hle/service/cecd/cecd_ndm.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CECD { + +class CECD_NDM : public Interface { +public: + CECD_NDM(); + + std::string GetPortName() const override { + return "cecd:ndm"; + } +}; + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp index 7477b9320..eacda7d41 100644 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -2,16 +2,34 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/service/cecd/cecd.h" #include "core/hle/service/cecd/cecd_s.h" namespace Service { namespace CECD { -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; +static const Interface::FunctionInfo FunctionTable[] = { + // cecd:u shared commands + {0x000100C2, nullptr, "OpenRawFile"}, + {0x00020042, nullptr, "ReadRawFile"}, + {0x00030104, nullptr, "ReadMessage"}, + {0x00040106, nullptr, "ReadMessageWithHMAC"}, + {0x00050042, nullptr, "WriteRawFile"}, + {0x00060104, nullptr, "WriteMessage"}, + {0x00070106, nullptr, "WriteMessageWithHMAC"}, + {0x00080102, nullptr, "Delete"}, + {0x000A00C4, nullptr, "GetSystemInfo"}, + {0x000B0040, nullptr, "RunCommand"}, + {0x000C0040, nullptr, "RunCommandAlt"}, + {0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"}, + {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"}, + {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"}, + {0x00110104, nullptr, "OpenAndWrite"}, + {0x00120104, nullptr, "OpenAndRead"}, +}; -CECD_S_Interface::CECD_S_Interface() { - // Register(FunctionTable); +CECD_S::CECD_S() { + Register(FunctionTable); } } // namespace CECD diff --git a/src/core/hle/service/cecd/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h index df5c01849..ab6c6789a 100644 --- a/src/core/hle/service/cecd/cecd_s.h +++ b/src/core/hle/service/cecd/cecd_s.h @@ -9,9 +9,9 @@ namespace Service { namespace CECD { -class CECD_S_Interface : public Interface { +class CECD_S : public Interface { public: - CECD_S_Interface(); + CECD_S(); std::string GetPortName() const override { return "cecd:s"; diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp index 7d98ba6e9..3ed864f0b 100644 --- a/src/core/hle/service/cecd/cecd_u.cpp +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -9,6 +9,7 @@ namespace Service { namespace CECD { static const Interface::FunctionInfo FunctionTable[] = { + // cecd:u shared commands {0x000100C2, nullptr, "OpenRawFile"}, {0x00020042, nullptr, "ReadRawFile"}, {0x00030104, nullptr, "ReadMessage"}, @@ -27,7 +28,7 @@ static const Interface::FunctionInfo FunctionTable[] = { {0x00120104, nullptr, "OpenAndRead"}, }; -CECD_U_Interface::CECD_U_Interface() { +CECD_U::CECD_U() { Register(FunctionTable); } diff --git a/src/core/hle/service/cecd/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h index 394030ffc..16e874ff5 100644 --- a/src/core/hle/service/cecd/cecd_u.h +++ b/src/core/hle/service/cecd/cecd_u.h @@ -9,9 +9,9 @@ namespace Service { namespace CECD { -class CECD_U_Interface : public Interface { +class CECD_U : public Interface { public: - CECD_U_Interface(); + CECD_U(); std::string GetPortName() const override { return "cecd:u"; diff --git a/src/core/hle/service/dlp/dlp.h b/src/core/hle/service/dlp/dlp.h index ec2fe46e8..3185fe322 100644 --- a/src/core/hle/service/dlp/dlp.h +++ b/src/core/hle/service/dlp/dlp.h @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#pragma once + namespace Service { namespace DLP { diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index bef75f5df..09205e4b2 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -24,6 +24,7 @@ #include "core/file_sys/directory_backend.h" #include "core/file_sys/file_backend.h" #include "core/hle/hle.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -93,7 +94,7 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& File::~File() {} -ResultVal<bool> File::SyncRequest() { +void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); switch (cmd) { @@ -103,8 +104,8 @@ ResultVal<bool> File::SyncRequest() { u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32; u32 length = cmd_buff[3]; u32 address = cmd_buff[5]; - LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address); + LOG_TRACE(Service_FS, "Read %s: offset=0x%llx length=%d address=0x%x", GetName().c_str(), + offset, length, address); if (offset + length > backend->GetSize()) { LOG_ERROR(Service_FS, @@ -116,7 +117,7 @@ ResultVal<bool> File::SyncRequest() { ResultVal<size_t> read = backend->Read(offset, data.size(), data.data()); if (read.Failed()) { cmd_buff[1] = read.Code().raw; - return read.Code(); + return; } Memory::WriteBlock(address, data.data(), *read); cmd_buff[2] = static_cast<u32>(*read); @@ -129,22 +130,22 @@ ResultVal<bool> File::SyncRequest() { u32 length = cmd_buff[3]; u32 flush = cmd_buff[4]; u32 address = cmd_buff[6]; - LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); + LOG_TRACE(Service_FS, "Write %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", + GetName().c_str(), offset, length, address, flush); std::vector<u8> data(length); Memory::ReadBlock(address, data.data(), data.size()); ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); if (written.Failed()) { cmd_buff[1] = written.Code().raw; - return written.Code(); + return; } cmd_buff[2] = static_cast<u32>(*written); break; } case FileCommand::GetSize: { - LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); + LOG_TRACE(Service_FS, "GetSize %s", GetName().c_str()); u64 size = backend->GetSize(); cmd_buff[2] = (u32)size; cmd_buff[3] = size >> 32; @@ -153,14 +154,13 @@ ResultVal<bool> File::SyncRequest() { case FileCommand::SetSize: { u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), - size); + LOG_TRACE(Service_FS, "SetSize %s size=%llu", GetName().c_str(), size); backend->SetSize(size); break; } case FileCommand::Close: { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + LOG_TRACE(Service_FS, "Close %s", GetName().c_str()); backend->Close(); break; } @@ -173,7 +173,11 @@ ResultVal<bool> File::SyncRequest() { case FileCommand::OpenLinkFile: { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); - cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE); + auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); + ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .ValueOr(INVALID_HANDLE); break; } @@ -194,10 +198,9 @@ ResultVal<bool> File::SyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return error; + return; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return MakeResult<bool>(false); } Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, @@ -206,18 +209,16 @@ Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, Directory::~Directory() {} -ResultVal<bool> Directory::SyncRequest() { +void Directory::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); switch (cmd) { - // Read from directory... case DirectoryCommand::Read: { u32 count = cmd_buff[1]; u32 address = cmd_buff[3]; std::vector<FileSys::Entry> entries(count); - LOG_TRACE(Service_FS, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), - count); + LOG_TRACE(Service_FS, "Read %s: count=%d", GetName().c_str(), count); // Number of entries actually read u32 read = backend->Read(entries.size(), entries.data()); @@ -227,7 +228,7 @@ ResultVal<bool> Directory::SyncRequest() { } case DirectoryCommand::Close: { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + LOG_TRACE(Service_FS, "Close %s", GetName().c_str()); backend->Close(); break; } @@ -237,10 +238,9 @@ ResultVal<bool> Directory::SyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return MakeResult<bool>(false); + return; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return MakeResult<bool>(false); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -307,9 +307,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor return RESULT_SUCCESS; } -ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode) { +ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, + const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; @@ -318,8 +318,8 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han if (backend.Failed()) return backend.Code(); - auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path)); - return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); + auto file = std::shared_ptr<File>(new File(backend.MoveFrom(), path)); + return MakeResult<std::shared_ptr<File>>(std::move(file)); } ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { @@ -398,8 +398,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, } } -ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path) { +ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; @@ -408,8 +408,8 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a if (backend.Failed()) return backend.Code(); - auto directory = Kernel::SharedPtr<Directory>(new Directory(backend.MoveFrom(), path)); - return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); + auto directory = std::shared_ptr<Directory>(new Directory(backend.MoveFrom(), path)); + return MakeResult<std::shared_ptr<Directory>>(std::move(directory)); } ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 87089bd92..7ba62ede0 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -8,7 +8,7 @@ #include <string> #include "common/common_types.h" #include "core/file_sys/archive_backend.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" namespace FileSys { @@ -43,33 +43,37 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; typedef u64 ArchiveHandle; -class File : public Kernel::Session { +class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> { public: File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); ~File(); - std::string GetName() const override { + std::string GetName() const { return "Path: " + path.DebugStr(); } - ResultVal<bool> SyncRequest() override; FileSys::Path path; ///< Path of the file u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface + +protected: + void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; }; -class Directory : public Kernel::Session { +class Directory final : public SessionRequestHandler { public: Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); ~Directory(); - std::string GetName() const override { + std::string GetName() const { return "Directory: " + path.DebugStr(); } - ResultVal<bool> SyncRequest() override; FileSys::Path path; ///< Path of the directory std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface + +protected: + void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; }; /** @@ -99,11 +103,11 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor * @param archive_handle Handle to an open Archive object * @param path Path to the File inside of the Archive * @param mode Mode under which to open the File - * @return The opened File object as a Session + * @return The opened File object */ -ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode); +ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, + const FileSys::Mode mode); /** * Delete a File from an Archive @@ -178,10 +182,10 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return The opened Directory object as a Session + * @return The opened Directory object */ -ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path); +ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path); /** * Get the free space in an Archive diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index d6ab5b065..337da1387 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -8,6 +8,7 @@ #include "common/logging/log.h" #include "common/scope_exit.h" #include "common/string_util.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -17,7 +18,7 @@ // Namespace FS_User using Kernel::SharedPtr; -using Kernel::Session; +using Kernel::ServerSession; namespace Service { namespace FS { @@ -67,10 +68,16 @@ static void OpenFile(Service::Interface* self) { LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode); + ResultVal<std::shared_ptr<File>> file_res = + OpenFileFromArchive(archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); + std::shared_ptr<File> file = *file_res; + auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -127,10 +134,16 @@ static void OpenFileDirectly(Service::Interface* self) { } SCOPE_EXIT({ CloseArchive(*archive_handle); }); - ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); + ResultVal<std::shared_ptr<File>> file_res = + OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); + std::shared_ptr<File> file = *file_res; + auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", @@ -388,10 +401,16 @@ static void OpenDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size, dir_path.DebugStr().c_str()); - ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); + ResultVal<std::shared_ptr<Directory>> dir_res = + OpenDirectoryFromArchive(archive_handle, dir_path); cmd_buff[1] = dir_res.Code().raw; if (dir_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); + std::shared_ptr<Directory> directory = *dir_res; + auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); + directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 49f4836b4..947958703 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -636,6 +636,7 @@ static void TriggerCmdReqQueue(Interface* self) { * Inputs: * 0: Header 0x00180000 * Outputs: + * 0: Header Code[0x00180240] * 1: Result code * 2: Left framebuffer virtual address for the main screen * 3: Right framebuffer virtual address for the main screen @@ -658,18 +659,19 @@ static void ImportDisplayCaptureInfo(Interface* self) { FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0); FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1); + cmd_buff[0] = IPC::MakeHeader(0x18, 0x9, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + // Top Screen cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left; cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right; cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format; cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride; - + // Bottom Screen cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left; cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right; cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format; cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride; - cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_GSP, "called"); } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 99baded11..18a1b6a16 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -37,7 +37,8 @@ static int enable_gyroscope_count = 0; // positive means enabled static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { // 30 degree and 60 degree are angular thresholds for directions - constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; + constexpr float TAN30 = 0.577350269f; + constexpr float TAN60 = 1 / TAN30; // a circle pad radius greater than 40 will trigger circle pad direction constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; PadState state; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index effecc043..25a7aeea8 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -2,11 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <boost/range/algorithm_ext/erase.hpp> + #include "common/logging/log.h" #include "common/string_util.h" + +#include "core/hle/kernel/server_port.h" #include "core/hle/service/ac_u.h" -#include "core/hle/service/act_a.h" -#include "core/hle/service/act_u.h" +#include "core/hle/service/act/act.h" #include "core/hle/service/am/am.h" #include "core/hle/service/apt/apt.h" #include "core/hle/service/boss/boss.h" @@ -44,8 +47,8 @@ namespace Service { -std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; -std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; +std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; +std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; /** * Creates a function string for logging, complete with the name (or header code, depending @@ -64,7 +67,23 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -ResultVal<bool> Interface::SyncRequest() { +void SessionRequestHandler::ClientConnected( + Kernel::SharedPtr<Kernel::ServerSession> server_session) { + connected_sessions.push_back(server_session); +} + +void SessionRequestHandler::ClientDisconnected( + Kernel::SharedPtr<Kernel::ServerSession> server_session) { + boost::range::remove_erase(connected_sessions, server_session); +} + +Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} +Interface::~Interface() = default; + +void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { + // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which + // session triggered each command. + u32* cmd_buff = Kernel::GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -78,14 +97,12 @@ ResultVal<bool> Interface::SyncRequest() { // TODO(bunnei): Hack - ignore error cmd_buff[1] = 0; - return MakeResult<bool>(false); + return; } LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); itr->second.func(this); - - return MakeResult<bool>(false); // TODO: Implement return from actual function } void Interface::Register(const FunctionInfo* functions, size_t n) { @@ -100,11 +117,19 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); + auto ports = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr<Interface>(interface_)); + auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); + g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); } void AddService(Interface* interface_) { - g_srv_services.emplace(interface_->GetPortName(), interface_); + auto ports = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr<Interface>(interface_)); + auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); + g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); } /// Initialize ServiceManager @@ -113,6 +138,7 @@ void Init() { AddNamedPort(new ERR::ERR_F); FS::ArchiveInit(); + ACT::Init(); AM::Init(); APT::Init(); BOSS::Init(); @@ -132,8 +158,6 @@ void Init() { QTM::Init(); AddService(new AC::AC_U); - AddService(new ACT::ACT_A); - AddService(new ACT::ACT_U); AddService(new CSND::CSND_SND); AddService(new DSP_DSP::Interface); AddService(new GSP::GSP_GPU); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 29daacfc4..a7ba7688f 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -9,8 +9,15 @@ #include <unordered_map> #include <boost/container/flat_map.hpp> #include "common/common_types.h" -#include "core/hle/kernel/session.h" +#include "core/hle/ipc.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/thread.h" #include "core/hle/result.h" +#include "core/memory.h" + +namespace Kernel { +class ServerSession; +} //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service @@ -18,14 +25,63 @@ namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) +/// Arbitrary default number of maximum connections to an HLE service. +static const u32 DefaultMaxSessions = 10; + +/** + * Interface implemented by HLE Session handlers. + * This can be provided to a ServerSession in order to hook into several relevant events + * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. + */ +class SessionRequestHandler { +public: + /** + * Handles a sync request from the emulated application. + * @param server_session The ServerSession that was triggered for this sync request, + * it should be used to differentiate which client (As in ClientSession) we're answering to. + * TODO(Subv): Use a wrapper structure to hold all the information relevant to + * this request (ServerSession, Originator thread, Translated command buffer, etc). + * @returns ResultCode the result code of the translate operation. + */ + virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0; + + /** + * Signals that a client has just connected to this HLE handler and keeps the + * associated ServerSession alive for the duration of the connection. + * @param server_session Owning pointer to the ServerSession associated with the connection. + */ + void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); + + /** + * Signals that a client has just disconnected from this HLE handler and releases the + * associated ServerSession. + * @param server_session ServerSession associated with the connection. + */ + void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); -/// Interface to a CTROS service -class Interface : public Kernel::Session { - // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be - // just something that encapsulates a session and acts as a helper to implement service - // processes. +protected: + /// List of sessions that are connected to this handler. + /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list + // for the duration of the connection. + std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions; +}; + +/** + * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a + * table mapping header ids to handler functions. + */ +class Interface : public SessionRequestHandler { public: - std::string GetName() const override { + /** + * Creates an HLE interface with the specified max sessions. + * @param max_sessions Maximum number of sessions that can be + * connected to this service at the same time. + */ + Interface(u32 max_sessions = DefaultMaxSessions); + + virtual ~Interface(); + + std::string GetName() const { return GetPortName(); } @@ -33,6 +89,15 @@ public: version.raw = raw_version; } + /** + * Gets the maximum allowed number of sessions that can be connected to this service + * at the same time. + * @returns The maximum number of connections allowed. + */ + u32 GetMaxSessions() const { + return max_sessions; + } + typedef void (*Function)(Interface*); struct FunctionInfo { @@ -49,9 +114,9 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultVal<bool> SyncRequest() override; - protected: + void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; + /** * Registers the functions in the service */ @@ -71,6 +136,7 @@ protected: } version = {}; private: + u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle. boost::container::flat_map<u32, FunctionInfo> m_functions; }; @@ -81,9 +147,9 @@ void Init(); void Shutdown(); /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. -extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; +extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; +extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; /// Adds a service to the services table void AddService(Interface* interface_); diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index fd251fc0a..c3918cdd0 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/scope_exit.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" #include "core/hle/service/soc_u.h" #include "core/memory.h" diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index f8df38c42..3bd787147 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -2,9 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <tuple> + #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/service/srv.h" namespace Service { @@ -79,7 +83,15 @@ static void GetServiceHandle(Interface* self) { auto it = Service::g_srv_services.find(port_name); if (it != Service::g_srv_services.end()) { - cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom(); + auto client_port = it->second; + + auto client_session = client_port->Connect(); + res = client_session.Code(); + + if (client_session.Succeeded()) { + // Return the client session + cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); + } LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); } else { LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 6041ca42d..d3a9de879 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#pragma once + #include "core/hle/service/service.h" namespace Service { |