diff options
-rw-r--r-- | src/core/hle/service/am/am.cpp | 92 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/applets.cpp | 95 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/applets.h | 56 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.cpp | 43 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.h | 12 |
5 files changed, 194 insertions, 104 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d92a46b00..fd14af1e7 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -32,6 +32,9 @@ namespace Service::AM { +constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; +constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; + enum class AppletId : u32 { SoftwareKeyboard = 0x11, }; @@ -529,7 +532,8 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { public: explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet) - : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) { + : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)), + broker(std::make_shared<Applets::AppletDataBroker>()) { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, @@ -554,34 +558,16 @@ public: // clang-format on RegisterHandlers(functions); - - auto& kernel = Core::System::GetInstance().Kernel(); - state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "ILibraryAppletAccessor:StateChangedEvent"); - pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "ILibraryAppletAccessor:PopDataOutEvent"); - pop_interactive_out_data_event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } private: - void AppletStorageProxyOutData(IStorage storage) { - storage_stack.push(std::make_shared<IStorage>(storage)); - pop_out_data_event->Signal(); - } - - void AppletStorageProxyOutInteractiveData(IStorage storage) { - interactive_storage_stack.push(std::make_shared<IStorage>(storage)); - pop_interactive_out_data_event->Signal(); - } - void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { - state_changed_event->Signal(); + const auto event = broker->GetStateChangedEvent(); + event->Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(state_changed_event); + rb.PushCopyObjects(event); LOG_DEBUG(Service_AM, "called"); } @@ -604,14 +590,8 @@ private: void Start(Kernel::HLERequestContext& ctx) { ASSERT(applet != nullptr); - applet->Initialize(storage_stack); - while (!storage_stack.empty()) - storage_stack.pop(); - while (!interactive_storage_stack.empty()) - interactive_storage_stack.pop(); - applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); }, - [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }, - [this] { state_changed_event->Signal(); }); + applet->Initialize(broker); + applet->Execute(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -621,7 +601,7 @@ private: void PushInData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - storage_stack.push(rp.PopIpcInterface<IStorage>()); + broker->PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -632,28 +612,25 @@ private: void PopOutData(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - if (storage_stack.empty()) { - rb.Push(ResultCode(-1)); + const auto storage = broker->PopNormalDataToGame(); + if (storage == nullptr) { + rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IStorage>(std::move(storage_stack.front())); - - storage_stack.pop(); + rb.PushIpcInterface<IStorage>(std::move(*storage)); LOG_DEBUG(Service_AM, "called"); } void PushInteractiveInData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - interactive_storage_stack.push(rp.PopIpcInterface<IStorage>()); + broker->PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>()); ASSERT(applet->IsInitialized()); - applet->ReceiveInteractiveData(interactive_storage_stack.back()); - applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); }, - [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }, - [this] { state_changed_event->Signal(); }); + applet->ExecuteInteractive(); + applet->Execute(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -664,15 +641,14 @@ private: void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - if (interactive_storage_stack.empty()) { - rb.Push(ResultCode(-1)); + const auto storage = broker->PopInteractiveDataToGame(); + if (storage == nullptr) { + rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IStorage>(std::move(interactive_storage_stack.front())); - - interactive_storage_stack.pop(); + rb.PushIpcInterface<IStorage>(std::move(*storage)); LOG_DEBUG(Service_AM, "called"); } @@ -680,7 +656,7 @@ private: void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(pop_out_data_event); + rb.PushCopyObjects(broker->GetNormalDataEvent()); LOG_DEBUG(Service_AM, "called"); } @@ -688,17 +664,13 @@ private: void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(pop_interactive_out_data_event); + rb.PushCopyObjects(broker->GetInteractiveDataEvent()); LOG_DEBUG(Service_AM, "called"); } std::shared_ptr<Applets::Applet> applet; - std::queue<std::shared_ptr<IStorage>> storage_stack; - std::queue<std::shared_ptr<IStorage>> interactive_storage_stack; - Kernel::SharedPtr<Kernel::Event> state_changed_event; - Kernel::SharedPtr<Kernel::Event> pop_out_data_event; - Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event; + std::shared_ptr<Applets::AppletDataBroker> broker; }; void IStorage::Open(Kernel::HLERequestContext& ctx) { @@ -740,9 +712,12 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop<u64>()}; const std::vector<u8> data{ctx.ReadBuffer()}; - const auto size = std::min<std::size_t>(data.size(), backing.buffer.size() - offset); + if (data.size() > backing.buffer.size() - offset) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERR_SIZE_OUT_OF_BOUNDS); + } - std::memcpy(&backing.buffer[offset], data.data(), size); + std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -754,9 +729,12 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - std::size_t size{ctx.GetWriteBufferSize()}; + const std::size_t size{ctx.GetWriteBufferSize()}; - size = std::min<std::size_t>(size, backing.buffer.size() - offset); + if (size > backing.buffer.size() - offset) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERR_SIZE_OUT_OF_BOUNDS); + } ctx.WriteBuffer(backing.buffer.data() + offset, size); diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index be950d320..c81bd59b2 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -4,21 +4,108 @@ #include <cstring> #include "common/assert.h" +#include "core/core.h" #include "core/frontend/applets/software_keyboard.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/server_port.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" namespace Service::AM::Applets { +AppletDataBroker::AppletDataBroker() { + auto& kernel = Core::System::GetInstance().Kernel(); + state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, + "ILibraryAppletAccessor:StateChangedEvent"); + pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, + "ILibraryAppletAccessor:PopDataOutEvent"); + pop_interactive_out_data_event = Kernel::Event::Create( + kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); +} + +AppletDataBroker::~AppletDataBroker() = default; + +std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { + if (out_channel.empty()) + return nullptr; + + auto out = std::move(out_channel.front()); + out_channel.pop(); + return out; +} + +std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { + if (in_channel.empty()) + return nullptr; + + auto out = std::move(in_channel.front()); + in_channel.pop(); + return out; +} + +std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { + if (out_interactive_channel.empty()) + return nullptr; + + auto out = std::move(out_interactive_channel.front()); + out_interactive_channel.pop(); + return out; +} + +std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { + if (in_interactive_channel.empty()) + return nullptr; + + auto out = std::move(in_interactive_channel.front()); + in_interactive_channel.pop(); + return out; +} + +void AppletDataBroker::PushNormalDataFromGame(IStorage storage) { + in_channel.push(std::make_unique<IStorage>(storage)); +} + +void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { + out_channel.push(std::make_unique<IStorage>(storage)); + pop_out_data_event->Signal(); +} + +void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { + in_interactive_channel.push(std::make_unique<IStorage>(storage)); +} + +void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { + out_interactive_channel.push(std::make_unique<IStorage>(storage)); + pop_interactive_out_data_event->Signal(); +} + +void AppletDataBroker::SignalStateChanged() const { + state_changed_event->Signal(); +} + +Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const { + return pop_out_data_event; +} + +Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const { + return pop_interactive_out_data_event; +} + +Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const { + return state_changed_event; +} + Applet::Applet() = default; Applet::~Applet() = default; -void Applet::Initialize(std::queue<std::shared_ptr<IStorage>> storage) { - storage_stack = std::move(storage); +void Applet::Initialize(std::shared_ptr<AppletDataBroker> broker_) { + broker = std::move(broker_); + + const auto common = broker->PopNormalDataToApplet(); + ASSERT(common != nullptr); - const auto common_data = storage_stack.front()->GetData(); - storage_stack.pop(); + const auto common_data = common->GetData(); ASSERT(common_data.size() >= sizeof(CommonArguments)); std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index a6a9bf77b..136445649 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -8,35 +8,67 @@ #include <memory> #include <queue> #include "common/swap.h" +#include "core/hle/kernel/event.h" union ResultCode; -namespace Frontend { -class SoftwareKeyboardApplet; -} - namespace Service::AM { class IStorage; namespace Applets { -using AppletStorageProxyFunction = std::function<void(IStorage)>; -using AppletStateProxyFunction = std::function<void()>; +class AppletDataBroker final { +public: + AppletDataBroker(); + ~AppletDataBroker(); + + std::unique_ptr<IStorage> PopNormalDataToGame(); + std::unique_ptr<IStorage> PopNormalDataToApplet(); + + std::unique_ptr<IStorage> PopInteractiveDataToGame(); + std::unique_ptr<IStorage> PopInteractiveDataToApplet(); + + void PushNormalDataFromGame(IStorage storage); + void PushNormalDataFromApplet(IStorage storage); + + void PushInteractiveDataFromGame(IStorage storage); + void PushInteractiveDataFromApplet(IStorage storage); + + void SignalStateChanged() const; + + Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const; + Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const; + Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const; + +private: + // Queues are named from applet's perspective + std::queue<std::unique_ptr<IStorage>> + in_channel; // PopNormalDataToApplet and PushNormalDataFromGame + std::queue<std::unique_ptr<IStorage>> + out_channel; // PopNormalDataToGame and PushNormalDataFromApplet + std::queue<std::unique_ptr<IStorage>> + in_interactive_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame + std::queue<std::unique_ptr<IStorage>> + out_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet + + Kernel::SharedPtr<Kernel::Event> state_changed_event; + Kernel::SharedPtr<Kernel::Event> pop_out_data_event; // Signaled on PushNormalDataFromApplet + Kernel::SharedPtr<Kernel::Event> + pop_interactive_out_data_event; // Signaled on PushInteractiveDataFromApplet +}; class Applet { public: Applet(); virtual ~Applet(); - virtual void Initialize(std::queue<std::shared_ptr<IStorage>> storage); + virtual void Initialize(std::shared_ptr<AppletDataBroker> broker); virtual bool TransactionComplete() const = 0; virtual ResultCode GetStatus() const = 0; - virtual void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) = 0; - virtual void Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data, - AppletStateProxyFunction state) = 0; + virtual void ExecuteInteractive() = 0; + virtual void Execute() = 0; bool IsInitialized() const { return initialized; @@ -54,7 +86,7 @@ protected: static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); CommonArguments common_args; - std::queue<std::shared_ptr<IStorage>> storage_stack; + std::shared_ptr<AppletDataBroker> broker; bool initialized = false; }; diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 816b5fb5f..ca9ef7e7d 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -42,22 +42,23 @@ SoftwareKeyboard::SoftwareKeyboard() = default; SoftwareKeyboard::~SoftwareKeyboard() = default; -void SoftwareKeyboard::Initialize(std::queue<std::shared_ptr<IStorage>> storage_) { +void SoftwareKeyboard::Initialize(std::shared_ptr<AppletDataBroker> broker_) { complete = false; initial_text.clear(); final_data.clear(); - Applet::Initialize(std::move(storage_)); + Applet::Initialize(std::move(broker_)); - ASSERT(storage_stack.size() >= 2); - const auto& keyboard_config = storage_stack.front()->GetData(); - storage_stack.pop(); + const auto keyboard_config_storage = broker->PopNormalDataToApplet(); + ASSERT(keyboard_config_storage != nullptr); + const auto& keyboard_config = keyboard_config_storage->GetData(); ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); - const auto& work_buffer = storage_stack.front()->GetData(); - storage_stack.pop(); + const auto work_buffer_storage = broker->PopNormalDataToApplet(); + ASSERT(work_buffer_storage != nullptr); + const auto& work_buffer = work_buffer_storage->GetData(); if (config.initial_string_size == 0) return; @@ -76,10 +77,12 @@ ResultCode SoftwareKeyboard::GetStatus() const { return status; } -void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) { +void SoftwareKeyboard::ExecuteInteractive() { if (complete) return; + const auto storage = broker->PopInteractiveDataToApplet(); + ASSERT(storage != nullptr); const auto data = storage->GetData(); const auto status = static_cast<bool>(data[0]); @@ -91,15 +94,14 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; std::memcpy(string.data(), data.data() + 4, string.size() * 2); frontend.SendTextCheckDialog( - Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), state); + Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), + [this] { broker->SignalStateChanged(); }); } } -void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data, - AppletStateProxyFunction state) { +void SoftwareKeyboard::Execute() { if (complete) { - out_data(IStorage{final_data}); + broker->PushNormalDataFromApplet(IStorage{final_data}); return; } @@ -107,9 +109,6 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, const auto parameters = ConvertToFrontendParameters(config, initial_text); - this->out_data = out_data; - this->out_interactive_data = out_interactive_data; - this->state = state; frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, parameters); } @@ -147,19 +146,19 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { final_data = output_main; if (complete) { - out_data(IStorage{output_main}); + broker->PushNormalDataFromApplet(IStorage{output_main}); } else { - out_data(IStorage{output_main}); - out_interactive_data(IStorage{output_sub}); + broker->PushNormalDataFromApplet(IStorage{output_main}); + broker->PushInteractiveDataFromApplet(IStorage{output_sub}); } - state(); + broker->SignalStateChanged(); } else { status = ResultCode(-1); output_main[0] = 1; complete = true; - out_data(IStorage{output_main}); - state(); + broker->PushNormalDataFromApplet(IStorage{output_main}); + broker->SignalStateChanged(); } } } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index e0a9479c2..405c58851 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -50,14 +50,12 @@ public: SoftwareKeyboard(); ~SoftwareKeyboard() override; - void Initialize(std::queue<std::shared_ptr<IStorage>> storage) override; + void Initialize(std::shared_ptr<AppletDataBroker> broker) override; bool TransactionComplete() const override; ResultCode GetStatus() const override; - void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) override; - void Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data, - AppletStateProxyFunction state) override; + void ExecuteInteractive() override; + void Execute() override; void WriteText(std::optional<std::u16string> text); @@ -67,10 +65,6 @@ private: bool complete = false; std::vector<u8> final_data; ResultCode status = ResultCode(-1); - - AppletStorageProxyFunction out_data; - AppletStorageProxyFunction out_interactive_data; - AppletStateProxyFunction state; }; } // namespace Service::AM::Applets |