From dec0571eeefb8811f909f6b53a91268393b56fa5 Mon Sep 17 00:00:00 2001 From: MCredstoner2004 Date: Sat, 9 Apr 2022 22:16:11 -0500 Subject: [PATCH] Infrastructure for applets to be implemented This removes a stub for an applet and implements several applet related service calls. --- app/CMakeLists.txt | 4 + .../cpp/skyline/applet/applet_creator.cpp | 18 +++++ .../main/cpp/skyline/applet/applet_creator.h | 81 +++++++++++++++++++ app/src/main/cpp/skyline/kernel/ipc.h | 16 ++++ .../skyline/services/am/applet/IApplet.cpp | 43 ++++++++++ .../cpp/skyline/services/am/applet/IApplet.h | 71 ++++++++++++++++ .../am/applet/ILibraryAppletAccessor.cpp | 60 ++++++++++---- .../am/applet/ILibraryAppletAccessor.h | 51 +++++++++++- .../am/controller/IApplicationFunctions.cpp | 4 +- .../am/controller/ILibraryAppletCreator.cpp | 21 ++++- .../am/controller/ILibraryAppletCreator.h | 11 ++- .../skyline/services/am/storage/IStorage.cpp | 6 +- .../skyline/services/am/storage/IStorage.h | 21 +++-- .../services/am/storage/IStorageAccessor.cpp | 18 +++-- .../services/am/storage/IStorageAccessor.h | 1 + .../am/storage/TransferMemoryIStorage.cpp | 16 ++++ .../am/storage/TransferMemoryIStorage.h | 26 ++++++ .../services/am/storage/VectorIStorage.cpp | 18 +++++ .../services/am/storage/VectorIStorage.h | 26 ++++++ .../services/applet/common_arguments.h | 30 +++++++ .../main/cpp/skyline/services/base_service.h | 2 +- 21 files changed, 500 insertions(+), 44 deletions(-) create mode 100644 app/src/main/cpp/skyline/applet/applet_creator.cpp create mode 100644 app/src/main/cpp/skyline/applet/applet_creator.h create mode 100644 app/src/main/cpp/skyline/services/am/applet/IApplet.cpp create mode 100644 app/src/main/cpp/skyline/services/am/applet/IApplet.h create mode 100644 app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.cpp create mode 100644 app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.h create mode 100644 app/src/main/cpp/skyline/services/am/storage/VectorIStorage.cpp create mode 100644 app/src/main/cpp/skyline/services/am/storage/VectorIStorage.h create mode 100644 app/src/main/cpp/skyline/services/applet/common_arguments.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index deabc37c..428932d3 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -241,8 +241,12 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/am/controller/ISelfController.cpp ${source_DIR}/skyline/services/am/controller/IWindowController.cpp ${source_DIR}/skyline/services/am/storage/IStorage.cpp + ${source_DIR}/skyline/services/am/storage/VectorIStorage.cpp + ${source_DIR}/skyline/services/am/storage/TransferMemoryIStorage.cpp ${source_DIR}/skyline/services/am/storage/IStorageAccessor.cpp ${source_DIR}/skyline/services/am/applet/ILibraryAppletAccessor.cpp + ${source_DIR}/skyline/services/am/applet/IApplet.cpp + ${source_DIR}/skyline/applet/applet_creator.cpp ${source_DIR}/skyline/services/codec/IHardwareOpusDecoder.cpp ${source_DIR}/skyline/services/codec/IHardwareOpusDecoderManager.cpp ${source_DIR}/skyline/services/hid/IHidServer.cpp diff --git a/app/src/main/cpp/skyline/applet/applet_creator.cpp b/app/src/main/cpp/skyline/applet/applet_creator.cpp new file mode 100644 index 00000000..0ed73fe1 --- /dev/null +++ b/app/src/main/cpp/skyline/applet/applet_creator.cpp @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "applet_creator.h" + +namespace skyline::applet { + std::shared_ptr CreateApplet( + const DeviceState &state, service::ServiceManager &manager, + applet::AppletId appletId, const std::shared_ptr &onAppletStateChanged, + const std::shared_ptr &onNormalDataPushFromApplet, + const std::shared_ptr &onInteractiveDataPushFromApplet, + service::applet::LibraryAppletMode appletMode) { + switch (appletId) { + default: + throw exception("Unimplemented Applet: 0x{:X} ({})", static_cast(appletId), ToString(appletId)); + } + } +} diff --git a/app/src/main/cpp/skyline/applet/applet_creator.h b/app/src/main/cpp/skyline/applet/applet_creator.h new file mode 100644 index 00000000..736dca8f --- /dev/null +++ b/app/src/main/cpp/skyline/applet/applet_creator.h @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include +#include + +namespace skyline::applet { + #define APPLETS \ + APPLET_ENTRY(None, 0x000) \ + APPLET_ENTRY(Application, 0x001) \ + APPLET_ENTRY(OverlayApplet, 0x002) \ + APPLET_ENTRY(SystemAppletMenu, 0x003) \ + APPLET_ENTRY(SystemApplication, 0x004) \ + APPLET_ENTRY(LibraryAppletAuth, 0x00A) \ + APPLET_ENTRY(LibraryAppletCabinet, 0x00B) \ + APPLET_ENTRY(LibraryAppletController, 0x00C) \ + APPLET_ENTRY(LibraryAppletDataErase, 0x00D) \ + APPLET_ENTRY(LibraryAppletError, 0x00E) \ + APPLET_ENTRY(LibraryAppletNetConnect, 0x00F) \ + APPLET_ENTRY(LibraryAppletPlayerSelect, 0x010) \ + APPLET_ENTRY(LibraryAppletSwkbd, 0x011) \ + APPLET_ENTRY(LibraryAppletMiiEdit, 0x012) \ + APPLET_ENTRY(LibraryAppletWeb, 0x013) \ + APPLET_ENTRY(LibraryAppletShop, 0x014) \ + APPLET_ENTRY(LibraryAppletPhotoViewer, 0x015) \ + APPLET_ENTRY(LibraryAppletSet, 0x016) \ + APPLET_ENTRY(LibraryAppletOfflineWeb, 0x017) \ + APPLET_ENTRY(LibraryAppletLoginShare, 0x018) \ + APPLET_ENTRY(LibraryAppletWifiWebAuth, 0x019) \ + APPLET_ENTRY(LibraryAppletMyPage, 0x01A) \ + APPLET_ENTRY(LibraryAppletGift, 0x01B) \ + APPLET_ENTRY(LibraryAppletUserMigration, 0x01C) \ + APPLET_ENTRY(LibraryAppletPreomiaSys, 0x01D) \ + APPLET_ENTRY(LibraryAppletStory, 0x01E) \ + APPLET_ENTRY(LibraryAppletPreomiaUsr, 0x01F) \ + APPLET_ENTRY(LibraryAppletPreomiaUsrDummy, 0x020) \ + APPLET_ENTRY(LibraryAppletSample, 0x021) \ + APPLET_ENTRY(DevlopmentTool, 0x3E8) \ + APPLET_ENTRY(CombinationLA, 0x3F1) \ + APPLET_ENTRY(AeSystemApplet, 0x3F2) \ + APPLET_ENTRY(AeOverlayApplet, 0x3F3) \ + APPLET_ENTRY(AeStarter, 0x3F4) \ + APPLET_ENTRY(AeLibraryAppletAlone, 0x3F5) \ + APPLET_ENTRY(AeLibraryApplet1, 0x3F6) \ + APPLET_ENTRY(AeLibraryApplet2, 0x3F7) \ + APPLET_ENTRY(AeLibraryApplet3, 0x3F8) \ + APPLET_ENTRY(AeLibraryApplet4, 0x3F9) \ + APPLET_ENTRY(AppletISA, 0x3FA) \ + APPLET_ENTRY(AppletIOA, 0x3FB) \ + APPLET_ENTRY(AppletISTA, 0x3FC) \ + APPLET_ENTRY(AppletILA1, 0x3FD) \ + APPLET_ENTRY(AppletILA2, 0x3FE) + + /** + * @url https://switchbrew.org/wiki/Applet_Manager_services#AppletId + */ + enum class AppletId : u32 { + #define APPLET_ENTRY(name, id) name = id, + APPLETS + #undef APPLET_ENTRY + }; + + #define APPLET_ENTRY(name, id) ENUM_CASE(name); + + ENUM_STRING(AppletId, APPLETS) + + #undef APPLET_ENTRY + + /** + * @brief Creates an Applet of the appropiate class depending on the AppletId + */ + std::shared_ptr CreateApplet( + const DeviceState &state, service::ServiceManager &manager, + applet::AppletId appletId, const std::shared_ptr &onAppletStateChanged, + const std::shared_ptr &onNormalDataPushFromApplet, + const std::shared_ptr &onInteractiveDataPushFromApplet, + service::applet::LibraryAppletMode appletMode); +} diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h index 2a2e9b6c..eeda4dc5 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -4,6 +4,8 @@ #pragma once #include +#include "types/KSession.h" +#include "types/KProcess.h" namespace skyline { namespace constant { @@ -231,6 +233,20 @@ namespace skyline { return view; } + /** + * @brief Pops a Service object from the response as a domain or kernel handle + */ + template + std::shared_ptr PopService(u32 id, type::KSession &session) { + std::shared_ptr serviceObject; + if (session.isDomain) + serviceObject = session.domains.at(domainObjects.at(id)); + else + serviceObject = session.state.process->GetHandle(moveHandles.at(id))->serviceObject; + + return std::static_pointer_cast(serviceObject); + } + /** * @brief Skips an object to pop off the top */ diff --git a/app/src/main/cpp/skyline/services/am/applet/IApplet.cpp b/app/src/main/cpp/skyline/services/am/applet/IApplet.cpp new file mode 100644 index 00000000..c7382d27 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/applet/IApplet.cpp @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "IApplet.h" + +namespace skyline::service::am { + + IApplet::IApplet(const DeviceState &state, ServiceManager &manager, std::shared_ptr onAppletStateChanged, std::shared_ptr onNormalDataPushFromApplet, std::shared_ptr onInteractiveDataPushFromApplet, applet::LibraryAppletMode appletMode) + : BaseService(state, manager), onAppletStateChanged(std::move(onAppletStateChanged)), + onNormalDataPushFromApplet(std::move(onNormalDataPushFromApplet)), + onInteractiveDataPushFromApplet(std::move(onInteractiveDataPushFromApplet)) {} + + IApplet::~IApplet() = default; + + void IApplet::PushNormalDataAndSignal(const std::shared_ptr &data) { + normalOutputData.emplace(data); + onNormalDataPushFromApplet->Signal(); + } + + void IApplet::PushInteractiveDataAndSignal(const std::shared_ptr &data) { + interactiveOutputData.emplace(data); + onInteractiveDataPushFromApplet->Signal(); + } + + std::shared_ptr IApplet::PopNormalAndClear() { + if (normalOutputData.empty()) + return {}; + std::shared_ptr data(normalOutputData.front()); + normalOutputData.pop(); + onNormalDataPushFromApplet->ResetSignal(); + return data; + } + + std::shared_ptr IApplet::PopInteractiveAndClear() { + if (interactiveOutputData.empty()) + return {}; + std::shared_ptr data(interactiveOutputData.front()); + interactiveOutputData.pop(); + onInteractiveDataPushFromApplet->ResetSignal(); + return data; + } + +} diff --git a/app/src/main/cpp/skyline/services/am/applet/IApplet.h b/app/src/main/cpp/skyline/services/am/applet/IApplet.h new file mode 100644 index 00000000..3d0c382a --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/applet/IApplet.h @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include +#include +#include + + +namespace skyline::service::am { + /** + * @brief The base class all Applets have to inherit from + */ + class IApplet : public BaseService { + private: + std::shared_ptr onNormalDataPushFromApplet; + std::shared_ptr onInteractiveDataPushFromApplet; + + protected: + std::shared_ptr onAppletStateChanged; + std::queue> normalOutputData; //!< Stores data sent by the applet so the guest can read it when it needs to + std::queue> interactiveOutputData; //!< Stores interactive data sent by the applet so the guest can read it when it needs to + + /** + * @brief Utility to send data to the guest and trigger the onNormalDataPushFromApplet event + */ + void PushNormalDataAndSignal(const std::shared_ptr &data); + + /** + * @brief Utility to send data to the guest and trigger the onInteractiveDataPushFromApplet event + */ + void PushInteractiveDataAndSignal(const std::shared_ptr &data); + + public: + IApplet(const DeviceState &state, ServiceManager &manager, std::shared_ptr onAppletStateChanged, std::shared_ptr onNormalDataPushFromApplet, std::shared_ptr onInteractiveDataPushFromApplet, applet::LibraryAppletMode appletMode); + + virtual ~IApplet(); + + /** + * @brief Called when the applet is started + */ + virtual Result Start() = 0; + + /** + * @brief Called when the applet is stopped + */ + virtual Result GetResult() = 0; + + /** + * @brief Called when data is pushed to the applet by the guest through the normal queue + */ + virtual void PushNormalDataToApplet(std::shared_ptr data) = 0; + + /** + * @brief Called when data is pushed to the applet by the guest through the interactive queue + */ + virtual void PushInteractiveDataToApplet(std::shared_ptr data) = 0; + + /** + * @brief Used by ILibraryAppletAccessor to pop data from the normal queue and reset the corresponding event + */ + std::shared_ptr PopNormalAndClear(); + + /** + * @brief Used by ILibraryAppletAccessor to pop data from the interactive queue and reset the corresponding event + */ + std::shared_ptr PopInteractiveAndClear(); + }; +} diff --git a/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.cpp b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.cpp index ce0172db..52b5b54d 100644 --- a/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.cpp +++ b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.cpp @@ -1,47 +1,73 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) +// Copyright © 2020 Ryujinx Team and Contributors #include #include -#include +#include +#include #include "ILibraryAppletAccessor.h" namespace skyline::service::am { - ILibraryAppletAccessor::ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager) : stateChangeEvent(std::make_shared(state, false)), BaseService(state, manager) {} + ILibraryAppletAccessor::ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager, skyline::applet::AppletId appletId, applet::LibraryAppletMode appletMode) + : BaseService(state, manager), + stateChangeEvent(std::make_shared(state, false)), + popNormalOutDataEvent((std::make_shared(state, false))), + popInteractiveOutDataEvent((std::make_shared(state, false))), + applet(skyline::applet::CreateApplet(state, manager, appletId, stateChangeEvent, popNormalOutDataEvent, popInteractiveOutDataEvent, appletMode)) { + stateChangeEventHandle = state.process->InsertItem(stateChangeEvent); + popNormalOutDataEventHandle = state.process->InsertItem(popNormalOutDataEvent); + popInteractiveOutDataEventHandle = state.process->InsertItem(popInteractiveOutDataEvent); + Logger::Debug("Applet accessor for {} ID created with appletMode 0x{:X}", ToString(appletId), appletMode); + } Result ILibraryAppletAccessor::GetAppletStateChangedEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - stateChangeEvent->Signal(); - - KHandle handle{state.process->InsertItem(stateChangeEvent)}; - Logger::Debug("Applet State Change Event Handle: 0x{:X}", handle); - - response.copyHandles.push_back(handle); + Logger::Debug("Applet State Change Event Handle: 0x{:X}", stateChangeEventHandle); + response.copyHandles.push_back(stateChangeEventHandle); return {}; } Result ILibraryAppletAccessor::Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + return applet->Start(); } Result ILibraryAppletAccessor::GetResult(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + return applet->GetResult(); } Result ILibraryAppletAccessor::PushInData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + applet->PushNormalDataToApplet(request.PopService(0, session)); + return {}; + } + + Result ILibraryAppletAccessor::PushInteractiveInData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + applet->PushInteractiveDataToApplet(request.PopService(0, session)); return {}; } Result ILibraryAppletAccessor::PopOutData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - constexpr u32 LaunchParameterMagic{0xC79497CA}; //!< The magic of the application launch parameters - constexpr size_t LaunchParameterSize{0x88}; //!< The size of the launch parameter IStorage + if (auto outIStorage{applet->PopNormalAndClear()}) { + manager.RegisterService(outIStorage, session, response); + return {}; + } + return result::NotAvailable; + } - auto storageService{std::make_shared(state, manager, LaunchParameterSize)}; + Result ILibraryAppletAccessor::PopInteractiveOutData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (auto outIStorage = applet->PopInteractiveAndClear()) { + manager.RegisterService(outIStorage, session, response); + return {}; + } + return result::NotAvailable; + } - storageService->Push(LaunchParameterMagic); - storageService->Push(1); - storageService->Push(constant::DefaultUserId); + Result ILibraryAppletAccessor::GetPopOutDataEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + response.copyHandles.push_back(popNormalOutDataEventHandle); + return {}; + } - manager.RegisterService(storageService, session, response); + Result ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + response.copyHandles.push_back(popInteractiveOutDataEventHandle); return {}; } } diff --git a/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.h b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.h index 072921ed..61e7d1bf 100644 --- a/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.h +++ b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.h @@ -5,21 +5,38 @@ #include #include +#include "IApplet.h" +#include namespace skyline::service::am { + namespace result { + constexpr Result ObjectInvalid(128, 500); + constexpr Result OutOfBounds(128, 503); + constexpr Result NotAvailable(128, 2); + } + /** * @brief ILibraryAppletAccessor is used to communicate with the library applet * @url https://switchbrew.org/wiki/Applet_Manager_services#ILibraryAppletAccessor */ class ILibraryAppletAccessor : public BaseService { private: - std::shared_ptr stateChangeEvent; //!< This KEvent is triggered when the applet's state changes + std::shared_ptr stateChangeEvent; + std::shared_ptr popNormalOutDataEvent; + std::shared_ptr popInteractiveOutDataEvent; + + KHandle stateChangeEventHandle{}; + KHandle popNormalOutDataEventHandle{}; + KHandle popInteractiveOutDataEventHandle{}; + + std::shared_ptr applet; public: - ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager); + ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager, skyline::applet::AppletId appletId, applet::LibraryAppletMode appletMode); /** * @brief Returns a handle to the library applet state change event + * @url https://switchbrew.org/wiki/Applet_Manager_services#GetAppletStateChangedEvent */ Result GetAppletStateChangedEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); @@ -47,12 +64,40 @@ namespace skyline::service::am { */ Result PopOutData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Pushes in data to the library applet, through the interactive queue + * @url https://switchbrew.org/wiki/Applet_Manager_services#PushInteractiveInData + */ + Result PushInteractiveInData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Receives data from the library applet, from the interactive queue + * @url https://switchbrew.org/wiki/Applet_Manager_services#PopInteractiveOutData + */ + Result PopInteractiveOutData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Gets te KEvent for when there's data to be popped by the guest on the normal queue + * @url https://switchbrew.org/wiki/Applet_Manager_services#GetPopOutDataEvent + */ + Result GetPopOutDataEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Gets the KEvent for when there's data to be popped by the guest on the interactive queue + * @url https://switchbrew.org/wiki/Applet_Manager_services#GetPopInteractiveOutDataEvent + */ + Result GetPopInteractiveOutDataEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + SERVICE_DECL( SFUNC(0x0, ILibraryAppletAccessor, GetAppletStateChangedEvent), SFUNC(0xA, ILibraryAppletAccessor, Start), SFUNC(0x1E, ILibraryAppletAccessor, GetResult), SFUNC(0x64, ILibraryAppletAccessor, PushInData), - SFUNC(0x65, ILibraryAppletAccessor, PopOutData) + SFUNC(0x65, ILibraryAppletAccessor, PopOutData), + SFUNC(0x67, ILibraryAppletAccessor, PushInteractiveInData), + SFUNC(0x68, ILibraryAppletAccessor, PopInteractiveOutData), + SFUNC(0x69, ILibraryAppletAccessor, GetPopOutDataEvent), + SFUNC(0x6A, ILibraryAppletAccessor, GetPopInteractiveOutDataEvent) ) }; } diff --git a/app/src/main/cpp/skyline/services/am/controller/IApplicationFunctions.cpp b/app/src/main/cpp/skyline/services/am/controller/IApplicationFunctions.cpp index 101c4123..b6012693 100644 --- a/app/src/main/cpp/skyline/services/am/controller/IApplicationFunctions.cpp +++ b/app/src/main/cpp/skyline/services/am/controller/IApplicationFunctions.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "IApplicationFunctions.h" namespace skyline::service::am { @@ -29,7 +29,7 @@ namespace skyline::service::am { return result::NotAvailable; case LaunchParameterKind::PreselectedUser: { - storageService = std::make_shared(state, manager, LaunchParameterSize); + storageService = std::make_shared(state, manager, LaunchParameterSize); storageService->Push(LaunchParameterMagic); storageService->Push(1); diff --git a/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.cpp b/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.cpp index 93e514e4..5a361c6c 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.cpp +++ b/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.cpp @@ -1,25 +1,38 @@ + // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include +#include +#include #include +#include +#include #include "ILibraryAppletCreator.h" namespace skyline::service::am { ILibraryAppletCreator::ILibraryAppletCreator(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} Result ILibraryAppletCreator::CreateLibraryApplet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(SRVREG(ILibraryAppletAccessor), session, response); + auto appletId{request.Pop()}; + auto appletMode{request.Pop()}; + manager.RegisterService(SRVREG(ILibraryAppletAccessor, appletId, appletMode), session, response); return {}; } Result ILibraryAppletCreator::CreateStorage(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto size{request.Pop()}; - if (size < 0) throw exception("Cannot create an IStorage with a negative size"); + manager.RegisterService(SRVREG(VectorIStorage, size), session, response); + return {}; + } - manager.RegisterService(std::make_shared(state, manager, size), session, response); + Result ILibraryAppletCreator::CreateTransferMemoryStorage(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + bool writable{request.Pop() != 0}; + i64 size{request.Pop()}; + if (size < 0) + throw exception("Cannot create an IStorage with a negative size"); + manager.RegisterService(SRVREG(TransferMemoryIStorage, state.process->GetHandle(request.copyHandles.at(0)), writable), session, response); return {}; } } diff --git a/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.h b/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.h index 75263675..7d98bce6 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.h +++ b/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.h @@ -20,14 +20,21 @@ namespace skyline::service::am { Result CreateLibraryApplet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** - * @brief Creates an IStorage that can be used by the application + * @brief Creates an IStorage that can be used by the application, backed by service-allocated memory * @url https://switchbrew.org/wiki/Applet_Manager_services#CreateStorage */ Result CreateStorage(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Creates an IStorage that can be used by the application, backed by the supplied transfer memory + * @url https://switchbrew.org/wiki/Applet_Manager_services#CreateTransferMemoryStorage + */ + Result CreateTransferMemoryStorage(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + SERVICE_DECL( SFUNC(0x0, ILibraryAppletCreator, CreateLibraryApplet), - SFUNC(0xA, ILibraryAppletCreator, CreateStorage) + SFUNC(0xA, ILibraryAppletCreator, CreateStorage), + SFUNC(0xB, ILibraryAppletCreator, CreateTransferMemoryStorage) ) }; } diff --git a/app/src/main/cpp/skyline/services/am/storage/IStorage.cpp b/app/src/main/cpp/skyline/services/am/storage/IStorage.cpp index 3a30eaec..50a834f2 100644 --- a/app/src/main/cpp/skyline/services/am/storage/IStorage.cpp +++ b/app/src/main/cpp/skyline/services/am/storage/IStorage.cpp @@ -5,10 +5,12 @@ #include "IStorage.h" namespace skyline::service::am { - IStorage::IStorage(const DeviceState &state, ServiceManager &manager, size_t size) : content(size, 0), BaseService(state, manager) {} + IStorage::IStorage(const DeviceState &state, ServiceManager &manager, bool writable) : writable(writable), BaseService(state, manager) {} Result IStorage::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(std::make_shared(state, manager, shared_from_this()), session, response); + manager.RegisterService(std::make_shared(state, manager, std::static_pointer_cast(shared_from_this())), session, response); return {}; } + + IStorage::~IStorage() = default; } diff --git a/app/src/main/cpp/skyline/services/am/storage/IStorage.h b/app/src/main/cpp/skyline/services/am/storage/IStorage.h index 54914a18..73941523 100644 --- a/app/src/main/cpp/skyline/services/am/storage/IStorage.h +++ b/app/src/main/cpp/skyline/services/am/storage/IStorage.h @@ -10,14 +10,23 @@ namespace skyline::service::am { * @brief IStorage is used to open an IStorageAccessor to access a region of memory * @url https://switchbrew.org/wiki/Applet_Manager_services#IStorage */ - class IStorage : public BaseService, public std::enable_shared_from_this { + class IStorage : public BaseService { + public: + bool writable; //!< Whether the storage is writable by the guest private: size_t offset{}; //!< The current offset within the content for pushing data - public: - std::vector content; //!< The container for this IStorage's contents + protected: + IStorage(const DeviceState &state, ServiceManager &manager, bool writable); - IStorage(const DeviceState &state, ServiceManager &manager, size_t size); + public: + + virtual ~IStorage(); + + /** + * @brief A span of the backing storage for this IStorage + */ + virtual span GetSpan() = 0; /** * @brief Returns an IStorageAccessor that can read and write data to an IStorage @@ -29,10 +38,10 @@ namespace skyline::service::am { */ template void Push(const ValueType &value) { - if (offset + sizeof(ValueType) > content.size()) + if (offset + sizeof(ValueType) > this->GetSpan().size()) throw exception("The supplied value cannot fit into the IStorage"); - std::memcpy(content.data() + offset, reinterpret_cast(&value), sizeof(ValueType)); + std::memcpy(this->GetSpan().data() + offset, reinterpret_cast(&value), sizeof(ValueType)); offset += sizeof(ValueType); } diff --git a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp index 897a075b..2ec6af53 100644 --- a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp +++ b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp @@ -8,20 +8,23 @@ namespace skyline::service::am { IStorageAccessor::IStorageAccessor(const DeviceState &state, ServiceManager &manager, std::shared_ptr parent) : parent(std::move(parent)), BaseService(state, manager) {} Result IStorageAccessor::GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(static_cast(parent->content.size())); + response.Push(static_cast(parent->GetSpan().size())); return {}; } Result IStorageAccessor::Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto offset{request.Pop()}; - if (offset < 0 || offset > parent->content.size()) + if (!parent->writable) + return result::ObjectInvalid; + auto storageSpan{parent->GetSpan()}; + if (offset < 0 || offset > storageSpan.size()) return result::OutOfBounds; - size_t size{std::min(request.inputBuf.at(0).size(), parent->content.size() - static_cast(offset))}; + size_t size{std::min(request.inputBuf.at(0).size(), storageSpan.size() - static_cast(offset))}; if (size) - span(parent->content).copy_from(request.inputBuf.at(0), size); + storageSpan.subspan(static_cast(offset)).copy_from(request.inputBuf.at(0), size); return {}; } @@ -29,13 +32,14 @@ namespace skyline::service::am { Result IStorageAccessor::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto offset{request.Pop()}; - if (offset < 0 || offset > parent->content.size()) + auto storageSpan{parent->GetSpan()}; + if (offset < 0 || offset > storageSpan.size()) return result::OutOfBounds; - size_t size{std::min(request.outputBuf.at(0).size(), parent->content.size() - static_cast(offset))}; + size_t size{std::min(request.outputBuf.at(0).size(), storageSpan.size() - static_cast(offset))}; if (size) - request.outputBuf.at(0).copy_from(span(parent->content.data() + offset, size)); + request.outputBuf.at(0).copy_from(span(storageSpan.data() + offset, size)); return {}; } diff --git a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h index d4a26820..0c253b45 100644 --- a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h +++ b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h @@ -7,6 +7,7 @@ namespace skyline::service::am { namespace result { + constexpr Result ObjectInvalid(128, 500); constexpr Result OutOfBounds(128, 503); } diff --git a/app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.cpp b/app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.cpp new file mode 100644 index 00000000..22ca06be --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.cpp @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "TransferMemoryIStorage.h" + +#include + +namespace skyline::service::am { + TransferMemoryIStorage::TransferMemoryIStorage(const DeviceState &state, ServiceManager &manager, std::shared_ptr transferMemory, bool writable) : transferMemory(std::move(transferMemory)), IStorage(state, manager, writable) {} + + span TransferMemoryIStorage::GetSpan() { + return transferMemory->Get(); + } + + TransferMemoryIStorage::~TransferMemoryIStorage() = default; +} diff --git a/app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.h b/app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.h new file mode 100644 index 00000000..609c2b24 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/TransferMemoryIStorage.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include +#include "IStorage.h" + +namespace skyline::service::am { + /** + * @brief An IStorage backed by a transfer memory supplied by the guest + */ + class TransferMemoryIStorage : public IStorage { + private: + std::shared_ptr transferMemory; + + public: + + TransferMemoryIStorage(const DeviceState &state, ServiceManager &manager, std::shared_ptr transferMemory, bool writable); + + ~TransferMemoryIStorage() override; + + virtual span GetSpan() override; + }; +} diff --git a/app/src/main/cpp/skyline/services/am/storage/VectorIStorage.cpp b/app/src/main/cpp/skyline/services/am/storage/VectorIStorage.cpp new file mode 100644 index 00000000..9bbea908 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/VectorIStorage.cpp @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "VectorIStorage.h" + +#include + +namespace skyline::service::am { + VectorIStorage::VectorIStorage(const DeviceState &state, ServiceManager &manager, size_t size) : content(size, 0), IStorage(state, manager, true) {} + + VectorIStorage::VectorIStorage(const DeviceState &state, ServiceManager &manager, std::vector data) : content(std::move(data)), IStorage(state, manager, true) {} + + span VectorIStorage::GetSpan() { + return content; + } + + VectorIStorage::~VectorIStorage() = default; +} diff --git a/app/src/main/cpp/skyline/services/am/storage/VectorIStorage.h b/app/src/main/cpp/skyline/services/am/storage/VectorIStorage.h new file mode 100644 index 00000000..e5b20cf9 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/VectorIStorage.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include "IStorage.h" + +namespace skyline::service::am { + /** + * @brief VectorIStorage is an IStorage backed by a vector + */ + class VectorIStorage : public IStorage { + private: + std::vector content; + + public: + VectorIStorage(const DeviceState &state, ServiceManager &manager, size_t size); + + VectorIStorage(const DeviceState &state, ServiceManager &manager, std::vector data); + + ~VectorIStorage() override; + + virtual span GetSpan() override; + }; +} diff --git a/app/src/main/cpp/skyline/services/applet/common_arguments.h b/app/src/main/cpp/skyline/services/applet/common_arguments.h new file mode 100644 index 00000000..c3865702 --- /dev/null +++ b/app/src/main/cpp/skyline/services/applet/common_arguments.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +namespace skyline::service::applet { + /** + * @brief Specifies how the applet should run + * @url https://switchbrew.org/wiki/Applet_Manager_services#LibraryAppletMode + */ + enum class LibraryAppletMode : u32 { + AllForeground = 0x0, + PartialForeground = 0x1, + NoUi = 0x2, + PartialForegroundWithIndirectDisplay = 0x3, + AllForegroundInitiallyHidden = 0x4, + }; + /** + * @brief Common arguments to all LibraryApplets + * @url https://switchbrew.org/wiki/Applet_Manager_services#CommonArguments + */ + struct CommonArguments { + u32 version; + u32 size; + u32 apiVersion; + u32 themeColor; + u64 playStartupSound; + u64 systemTick; + }; +} diff --git a/app/src/main/cpp/skyline/services/base_service.h b/app/src/main/cpp/skyline/services/base_service.h index 2e3a8867..35cd326b 100644 --- a/app/src/main/cpp/skyline/services/base_service.h +++ b/app/src/main/cpp/skyline/services/base_service.h @@ -40,7 +40,7 @@ namespace skyline::service { /** * @brief The base class for the HOS service interfaces hosted by sysmodules */ - class BaseService { + class BaseService : public std::enable_shared_from_this { private: std::string name; //!< The name of the service, it's only assigned after GetName is called and shouldn't be used directly