diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 95b98c2a..6eabd86c 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -86,6 +86,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/am/controller/IWindowController.cpp ${source_DIR}/skyline/services/am/storage/IStorage.cpp ${source_DIR}/skyline/services/am/storage/IStorageAccessor.cpp + ${source_DIR}/skyline/services/am/applet/ILibraryAppletAccessor.cpp ${source_DIR}/skyline/services/hid/IHidServer.cpp ${source_DIR}/skyline/services/hid/IAppletResource.cpp ${source_DIR}/skyline/services/timesrv/IStaticService.cpp diff --git a/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.cpp b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.cpp new file mode 100644 index 00000000..85dd1409 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.cpp @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include +#include +#include "ILibraryAppletAccessor.h" + +namespace skyline::service::am { + ILibraryAppletAccessor::ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager) : stateChangeEvent(std::make_shared(state)), BaseService(state, manager, Service::am_ILibraryAppletAccessor, "am:ILibraryAppletAccessor", { + {0x0, SFUNC(ILibraryAppletAccessor::GetAppletStateChangedEvent)}, + {0xa, SFUNC(ILibraryAppletAccessor::Start)}, + {0x1e, SFUNC(ILibraryAppletAccessor::GetResult)}, + {0x64, SFUNC(ILibraryAppletAccessor::PushInData)}, + {0x65, SFUNC(ILibraryAppletAccessor::PopOutData)}, + }) {} + + void ILibraryAppletAccessor::GetAppletStateChangedEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + stateChangeEvent->Signal(); + + KHandle handle = state.process->InsertItem(stateChangeEvent); + state.logger->Debug("Applet State Change Event Handle: 0x{:X}", handle); + + response.copyHandles.push_back(handle); + } + + void ILibraryAppletAccessor::Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} + + void ILibraryAppletAccessor::GetResult(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} + + void ILibraryAppletAccessor::PushInData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} + + void ILibraryAppletAccessor::PopOutData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + constexpr u32 LaunchParameterMagic = 0xc79497ca; //!< This is the magic of the application launch parameters + constexpr size_t LaunchParameterSize = 0x88; //!< This is the size of the launch parameter IStorage + + auto storageService = std::make_shared(state, manager, LaunchParameterSize); + + storageService->Push(LaunchParameterMagic); + storageService->Push(1); + storageService->Push(constant::DefaultUserId); + + manager.RegisterService(storageService, session, response); + } +} diff --git a/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.h b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.h new file mode 100644 index 00000000..fa57ada1 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/applet/ILibraryAppletAccessor.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include +#include + +namespace skyline::service::am { + /** + * @brief ILibraryAppletAccessor is used to communicate with the library applet (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 + + public: + ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager); + + /** + * @brief This function returns a handle to the library applet state change event + */ + void GetAppletStateChangedEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief This function starts the library applet (https://switchbrew.org/wiki/Applet_Manager_services#Start) + */ + void Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief This function returns the exit code of the library applet (https://switchbrew.org/wiki/Applet_Manager_services#GetResult) + */ + void GetResult(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief This function pushes in data to the library applet (https://switchbrew.org/wiki/Applet_Manager_services#PushInData) + */ + void PushInData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief This function receives data from the library applet (https://switchbrew.org/wiki/Applet_Manager_services#PopOutData) + */ + void PopOutData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; +} 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 f88dfdc9..e1e62af4 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.cpp +++ b/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.cpp @@ -1,9 +1,26 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include +#include #include "ILibraryAppletCreator.h" namespace skyline::service::am { ILibraryAppletCreator::ILibraryAppletCreator(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::am_ILibraryAppletCreator, "am:ILibraryAppletCreator", { + {0x0, SFUNC(ILibraryAppletCreator::CreateLibraryApplet)}, + {0xa, SFUNC(ILibraryAppletCreator::CreateStorage)} }) {} + + void ILibraryAppletCreator::CreateLibraryApplet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + manager.RegisterService(SRVREG(ILibraryAppletAccessor), session, response); + } + + void 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(std::make_shared(state, manager, size), session, response); + } } 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 86a13031..52d18ea5 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.h +++ b/app/src/main/cpp/skyline/services/am/controller/ILibraryAppletCreator.h @@ -13,5 +13,15 @@ namespace skyline::service::am { class ILibraryAppletCreator : public BaseService { public: ILibraryAppletCreator(const DeviceState &state, ServiceManager &manager); + + /** + * @brief This function returns a handle to a library applet accessor (https://switchbrew.org/wiki/Applet_Manager_services#CreateLibraryApplet) + */ + void CreateLibraryApplet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief This function creates an IStorage that can be used by the application (https://switchbrew.org/wiki/Applet_Manager_services#CreateStorage) + */ + void CreateStorage(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); }; } diff --git a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp index 3bc80ade..81b53671 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp +++ b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp @@ -7,7 +7,8 @@ #include "ISelfController.h" namespace skyline::service::am { - ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::am_ISelfController, "am:ISelfController", { + ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared(state)), BaseService(state, manager, Service::am_ISelfController, "am:ISelfController", { + {0x9, SFUNC(ISelfController::GetLibraryAppletLaunchableEvent)}, {0xB, SFUNC(ISelfController::SetOperationModeChangedNotification)}, {0xC, SFUNC(ISelfController::SetPerformanceModeChangedNotification)}, {0xD, SFUNC(ISelfController::SetFocusHandlingMode)}, @@ -15,6 +16,15 @@ namespace skyline::service::am { {0x28, SFUNC(ISelfController::CreateManagedDisplayLayer)} }) {} + void ISelfController::GetLibraryAppletLaunchableEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + libraryAppletLaunchableEvent->Signal(); + + KHandle handle = state.process->InsertItem(libraryAppletLaunchableEvent); + state.logger->Debug("Library Applet Launchable Event Handle: 0x{:X}", handle); + + response.copyHandles.push_back(handle); + } + void ISelfController::SetOperationModeChangedNotification(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} void ISelfController::SetPerformanceModeChangedNotification(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} diff --git a/app/src/main/cpp/skyline/services/am/controller/ISelfController.h b/app/src/main/cpp/skyline/services/am/controller/ISelfController.h index 9ef2de8d..1d82abe5 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ISelfController.h +++ b/app/src/main/cpp/skyline/services/am/controller/ISelfController.h @@ -11,9 +11,17 @@ namespace skyline::service::am { * @brief This has functions relating to an application's own current status (https://switchbrew.org/wiki/Applet_Manager_services#ISelfController) */ class ISelfController : public BaseService { + private: + std::shared_ptr libraryAppletLaunchableEvent; //!< This KEvent is triggered when the library applet is launchable + public: ISelfController(const DeviceState &state, ServiceManager &manager); + /** + * @brief This function obtains a handle to the library applet launchable event (https://switchbrew.org/wiki/Applet_Manager_services#GetLibraryAppletLaunchableEvent) + */ + void GetLibraryAppletLaunchableEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @brief This function takes a u8 bool flag and no output (Stubbed) (https://switchbrew.org/wiki/Applet_Manager_services#SetOperationModeChangedNotification) */ 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 56df0677..188c21cc 100644 --- a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp +++ b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp @@ -8,6 +8,7 @@ namespace skyline::service::am { IStorageAccessor::IStorageAccessor(const DeviceState &state, ServiceManager &manager, std::shared_ptr parent) : parent(parent), BaseService(state, manager, Service::am_IStorageAccessor, "am:IStorageAccessor", { {0x0, SFUNC(IStorageAccessor::GetSize)}, + {0xa, SFUNC(IStorageAccessor::Write)}, {0xb, SFUNC(IStorageAccessor::Read)} }) {} @@ -15,16 +16,26 @@ namespace skyline::service::am { response.Push(parent->content.size()); } - void IStorageAccessor::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + void IStorageAccessor::Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto offset = request.Pop(); + auto size = request.inputBuf.at(0).size; + + if (offset + size > parent->content.size()) + throw exception("Trying to write past the end of an IStorage"); + + if (offset < 0) + throw exception("Trying to write before the start of an IStorage"); + + state.process->ReadMemory(parent->content.data() + offset, request.inputBuf.at(0).address, size); + } + + void IStorageAccessor::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto offset = request.Pop(); auto size = request.outputBuf.at(0).size; if (offset + size > parent->content.size()) throw exception("Trying to read past the end of an IStorage"); - if (offset < 0) - throw exception("Trying to read before the start of an IStorage"); - state.process->WriteMemory(parent->content.data() + offset, request.outputBuf.at(0).address, size); } } 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 1be86fea..2a6b2e3a 100644 --- a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h +++ b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h @@ -24,6 +24,11 @@ namespace skyline::service::am { */ void GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief This writes a buffer to the storage at the specified offset + */ + void Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @brief This returns a buffer containing the contents of the storage at the specified offset */ diff --git a/app/src/main/cpp/skyline/services/base_service.h b/app/src/main/cpp/skyline/services/base_service.h index 78db9d71..6b017517 100644 --- a/app/src/main/cpp/skyline/services/base_service.h +++ b/app/src/main/cpp/skyline/services/base_service.h @@ -40,6 +40,7 @@ namespace skyline::service { am_IAudioController, am_IDisplayController, am_ILibraryAppletCreator, + am_ILibraryAppletAccessor, am_IDebugFunctions, am_IAppletCommonFunctions, am_IStorage,