summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/am/library_applet_creator.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/am/library_applet_creator.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp
new file mode 100644
index 000000000..47bab7528
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_creator.cpp
@@ -0,0 +1,271 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/service/am/applet_data_broker.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/frontend/applets.h"
+#include "core/hle/service/am/library_applet_accessor.h"
+#include "core/hle/service/am/library_applet_creator.h"
+#include "core/hle/service/am/library_applet_storage.h"
+#include "core/hle/service/am/storage.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::AM {
+
+namespace {
+
+AppletProgramId AppletIdToProgramId(AppletId applet_id) {
+ switch (applet_id) {
+ case AppletId::OverlayDisplay:
+ return AppletProgramId::OverlayDisplay;
+ case AppletId::QLaunch:
+ return AppletProgramId::QLaunch;
+ case AppletId::Starter:
+ return AppletProgramId::Starter;
+ case AppletId::Auth:
+ return AppletProgramId::Auth;
+ case AppletId::Cabinet:
+ return AppletProgramId::Cabinet;
+ case AppletId::Controller:
+ return AppletProgramId::Controller;
+ case AppletId::DataErase:
+ return AppletProgramId::DataErase;
+ case AppletId::Error:
+ return AppletProgramId::Error;
+ case AppletId::NetConnect:
+ return AppletProgramId::NetConnect;
+ case AppletId::ProfileSelect:
+ return AppletProgramId::ProfileSelect;
+ case AppletId::SoftwareKeyboard:
+ return AppletProgramId::SoftwareKeyboard;
+ case AppletId::MiiEdit:
+ return AppletProgramId::MiiEdit;
+ case AppletId::Web:
+ return AppletProgramId::Web;
+ case AppletId::Shop:
+ return AppletProgramId::Shop;
+ case AppletId::PhotoViewer:
+ return AppletProgramId::PhotoViewer;
+ case AppletId::Settings:
+ return AppletProgramId::Settings;
+ case AppletId::OfflineWeb:
+ return AppletProgramId::OfflineWeb;
+ case AppletId::LoginShare:
+ return AppletProgramId::LoginShare;
+ case AppletId::WebAuth:
+ return AppletProgramId::WebAuth;
+ case AppletId::MyPage:
+ return AppletProgramId::MyPage;
+ default:
+ return static_cast<AppletProgramId>(0);
+ }
+}
+
+[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
+ Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
+ LibraryAppletMode mode) {
+ const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
+ if (program_id == 0) {
+ // Unknown applet
+ return {};
+ }
+
+ auto process = std::make_unique<Process>(system);
+ if (!process->Initialize(program_id)) {
+ // Couldn't initialize the guest process
+ return {};
+ }
+
+ const auto applet = std::make_shared<Applet>(system, std::move(process));
+ applet->program_id = program_id;
+ applet->applet_id = applet_id;
+ applet->type = AppletType::LibraryApplet;
+ applet->library_applet_mode = mode;
+
+ // Set focus state
+ switch (mode) {
+ case LibraryAppletMode::AllForeground:
+ case LibraryAppletMode::NoUI:
+ applet->focus_state = FocusState::InFocus;
+ applet->hid_registration.EnableAppletToGetInput(true);
+ applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
+ applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
+ break;
+ case LibraryAppletMode::AllForegroundInitiallyHidden:
+ applet->system_buffer_manager.SetWindowVisibility(false);
+ applet->focus_state = FocusState::NotInFocus;
+ applet->hid_registration.EnableAppletToGetInput(false);
+ applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
+ break;
+ case LibraryAppletMode::Background:
+ case LibraryAppletMode::BackgroundIndirectDisplay:
+ default:
+ applet->focus_state = FocusState::Background;
+ applet->hid_registration.EnableAppletToGetInput(true);
+ applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
+ break;
+ }
+
+ auto broker = std::make_shared<AppletDataBroker>(system);
+ applet->caller_applet = caller_applet;
+ applet->caller_applet_broker = broker;
+
+ system.GetAppletManager().InsertApplet(applet);
+
+ return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
+}
+
+[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
+ Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
+ LibraryAppletMode mode) {
+ const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
+
+ auto process = std::make_unique<Process>(system);
+ auto applet = std::make_shared<Applet>(system, std::move(process));
+ applet->program_id = program_id;
+ applet->applet_id = applet_id;
+ applet->type = AppletType::LibraryApplet;
+ applet->library_applet_mode = mode;
+
+ auto storage = std::make_shared<AppletDataBroker>(system);
+ applet->caller_applet = caller_applet;
+ applet->caller_applet_broker = storage;
+ applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
+
+ return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
+}
+
+} // namespace
+
+ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_)
+ : ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} {
+ static const FunctionInfo functions[] = {
+ {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
+ {1, nullptr, "TerminateAllLibraryApplets"},
+ {2, nullptr, "AreAnyLibraryAppletsLeft"},
+ {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
+ {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
+ {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
+ };
+ RegisterHandlers(functions);
+}
+
+ILibraryAppletCreator::~ILibraryAppletCreator() = default;
+
+void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto applet_id = rp.PopRaw<AppletId>();
+ const auto applet_mode = rp.PopRaw<LibraryAppletMode>();
+
+ LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
+ applet_mode);
+
+ auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
+ if (!library_applet) {
+ LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ // Applet is created, can now be launched.
+ applet->library_applet_launchable_event.Signal();
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<ILibraryAppletAccessor>(library_applet);
+}
+
+void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const s64 size{rp.Pop<s64>()};
+
+ LOG_DEBUG(Service_AM, "called, size={}", size);
+
+ if (size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ std::vector<u8> data(size);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IStorage>(system, AM::CreateStorage(std::move(data)));
+}
+
+void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ struct Parameters {
+ bool is_writable;
+ s64 size;
+ };
+
+ const auto params{rp.PopRaw<Parameters>()};
+ const auto handle{ctx.GetCopyHandle(0)};
+
+ LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable,
+ params.size, handle);
+
+ if (params.size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
+
+ if (transfer_mem.IsNull()) {
+ LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IStorage>(
+ system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(),
+ params.is_writable, params.size));
+}
+
+void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const s64 size{rp.Pop<s64>()};
+ const auto handle{ctx.GetCopyHandle(0)};
+
+ LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
+
+ if (size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
+
+ if (transfer_mem.IsNull()) {
+ LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IStorage>(
+ system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size));
+}
+
+} // namespace Service::AM