From 8985fe705feba9c7f5344845dad29b754cfe0291 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sat, 4 Jul 2020 20:15:33 +0100 Subject: [PATCH] Implement IStorage services in Applet Manager In the case of am, IStorage is used to exchange buffers of data such as application launch parameters or an applets result. It has no relation to fsp-srv's IStorage. --- app/CMakeLists.txt | 2 + .../skyline/services/am/storage/IStorage.cpp | 15 +++++++ .../skyline/services/am/storage/IStorage.h | 41 +++++++++++++++++++ .../services/am/storage/IStorageAccessor.cpp | 30 ++++++++++++++ .../services/am/storage/IStorageAccessor.h | 32 +++++++++++++++ .../main/cpp/skyline/services/base_service.h | 2 + 6 files changed, 122 insertions(+) create mode 100644 app/src/main/cpp/skyline/services/am/storage/IStorage.cpp create mode 100644 app/src/main/cpp/skyline/services/am/storage/IStorage.h create mode 100644 app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp create mode 100644 app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 36d52cb9..19736525 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -83,6 +83,8 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/am/controller/ILibraryAppletCreator.cpp ${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/IStorageAccessor.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/storage/IStorage.cpp b/app/src/main/cpp/skyline/services/am/storage/IStorage.cpp new file mode 100644 index 00000000..28c86032 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/IStorage.cpp @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "IStorageAccessor.h" +#include "IStorage.h" + +namespace skyline::service::am { + IStorage::IStorage(const DeviceState &state, ServiceManager &manager, size_t size) : content(size), BaseService(state, manager, Service::am_IStorage, "am:IStorage", { + {0x0, SFUNC(IStorage::Open)} + }) {} + + void IStorage::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + manager.RegisterService(std::make_shared(state, manager, shared_from_this()), session, response); + } +} diff --git a/app/src/main/cpp/skyline/services/am/storage/IStorage.h b/app/src/main/cpp/skyline/services/am/storage/IStorage.h new file mode 100644 index 00000000..2780c3c2 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/IStorage.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include + +namespace skyline::service::am { + /** + * @brief IStorage is used to open an IStorageAccessor to access a region of memory (https://switchbrew.org/wiki/Applet_Manager_services#IStorage) + */ + class IStorage : public BaseService, public std::enable_shared_from_this { + private: + size_t offset{}; //!< The current offset within the content for pushing data + + public: + std::vector content; //!< The container for this IStorage's contents + + IStorage(const DeviceState &state, ServiceManager &manager, size_t size); + + /** + * @brief This returns an IStorageAccessor that can read and write data to an IStorage + */ + void Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief This function writes an object to the storage + * @tparam ValueType The type of the object to write + * @param value A reference to the object to be written + */ + template + inline void Push(const ValueType &value) { + if (offset + sizeof(ValueType) > content.size()) + throw exception("The supplied value cannot fit into the IStorage"); + + std::memcpy(content.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 new file mode 100644 index 00000000..56df0677 --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include "IStorage.h" +#include "IStorageAccessor.h" + +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)}, + {0xb, SFUNC(IStorageAccessor::Read)} + }) {} + + void IStorageAccessor::GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + response.Push(parent->content.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 new file mode 100644 index 00000000..1be86fea --- /dev/null +++ b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include + +namespace skyline::service::am { + class IStorage; + + /** + * @brief IStorageAccessor is used read and write to an IStorage (https://switchbrew.org/wiki/Applet_Manager_services#IStorageAccessor) + */ + class IStorageAccessor : public BaseService { + private: + std::shared_ptr parent; //!< The parent IStorage of the accessor + + public: + IStorageAccessor(const DeviceState &state, ServiceManager &manager, std::shared_ptr parent); + + /** + * @brief This returns the size of the storage in bytes + */ + void GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief This returns a buffer containing the contents of the storage at the specified offset + */ + void Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; +} diff --git a/app/src/main/cpp/skyline/services/base_service.h b/app/src/main/cpp/skyline/services/base_service.h index 57959a51..1a36aa34 100644 --- a/app/src/main/cpp/skyline/services/base_service.h +++ b/app/src/main/cpp/skyline/services/base_service.h @@ -42,6 +42,8 @@ namespace skyline::service { am_ILibraryAppletCreator, am_IDebugFunctions, am_IAppletCommonFunctions, + am_IStorage, + am_IStorageAccessor, audio_IAudioOutManager, audio_IAudioOut, audio_IAudioRendererManager,