From 0f8be2d2cc54feda0a52ec8f9633fd022879816a Mon Sep 17 00:00:00 2001 From: Subv Date: Fri, 4 Dec 2015 16:05:23 -0500 Subject: [PATCH] HLE/Applets: Implemented a dummy Mii Selector applet. This prevents some games (like Super Mario 3D Land) from freezing when trying to launch it, however, it's not complete and won't let you go past Mii selection as the parameter structure hasn't been reverse engineered yet. --- src/core/CMakeLists.txt | 2 + src/core/hle/applets/applet.cpp | 6 +++ src/core/hle/applets/mii_selector.cpp | 75 +++++++++++++++++++++++++++ src/core/hle/applets/mii_selector.h | 37 +++++++++++++ src/core/hle/service/apt/apt.cpp | 19 +++++++ src/core/hle/service/apt/apt.h | 17 +++++- src/core/hle/service/apt/apt_u.cpp | 2 +- 7 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/core/hle/applets/mii_selector.cpp create mode 100644 src/core/hle/applets/mii_selector.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 861b711c7a..d21f198e5e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -26,6 +26,7 @@ set(SRCS hle/config_mem.cpp hle/hle.cpp hle/applets/applet.cpp + hle/applets/mii_selector.cpp hle/applets/swkbd.cpp hle/kernel/address_arbiter.cpp hle/kernel/event.cpp @@ -155,6 +156,7 @@ set(HEADERS hle/function_wrappers.h hle/hle.h hle/applets/applet.h + hle/applets/mii_selector.h hle/applets/swkbd.h hle/kernel/address_arbiter.h hle/kernel/event.h diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index bc2a1829eb..90e1344372 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -12,6 +12,7 @@ #include "core/core_timing.h" #include "core/hle/applets/applet.h" +#include "core/hle/applets/mii_selector.h" #include "core/hle/applets/swkbd.h" #include "core/hle/result.h" #include "core/hle/service/apt/apt.h" @@ -47,7 +48,12 @@ ResultCode Applet::Create(Service::APT::AppletId id) { case Service::APT::AppletId::SoftwareKeyboard2: applets[id] = std::make_shared(id); break; + case Service::APT::AppletId::Ed1: + case Service::APT::AppletId::Ed2: + applets[id] = std::make_shared(id); + break; default: + LOG_ERROR(Service_APT, "Could not create applet %u", id); // TODO(Subv): Find the right error code return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent); } diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp new file mode 100644 index 0000000000..708d2f630b --- /dev/null +++ b/src/core/hle/applets/mii_selector.cpp @@ -0,0 +1,75 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" + +#include "core/hle/applets/mii_selector.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/result.h" + +#include "video_core/video_core.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace HLE { +namespace Applets { + +MiiSelector::MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) { + // Create the SharedMemory that will hold the framebuffer data + // TODO(Subv): What size should we use here? + using Kernel::MemoryPermission; + framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "MiiSelector Memory"); +} + +ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { + if (parameter.signal != static_cast(Service::APT::SignalType::LibAppJustStarted)) { + LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); + UNIMPLEMENTED(); + // TODO(Subv): Find the right error code + return ResultCode(-1); + } + + Service::APT::MessageParameter result; + // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo + result.signal = static_cast(Service::APT::SignalType::LibAppFinished); + result.data = nullptr; + result.buffer_size = 0; + result.destination_id = static_cast(Service::APT::AppletId::Application); + result.sender_id = static_cast(id); + result.object = framebuffer_memory; + + Service::APT::SendParameter(result); + return RESULT_SUCCESS; +} + +ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) { + started = true; + + // TODO(Subv): Set the expected fields in the response buffer before resending it to the application. + // TODO(Subv): Reverse the parameter format for the Mii Selector + + // Let the application know that we're closing + Service::APT::MessageParameter message; + message.buffer_size = parameter.buffer_size; + message.data = parameter.data; + message.signal = static_cast(Service::APT::SignalType::LibAppClosed); + message.destination_id = static_cast(Service::APT::AppletId::Application); + message.sender_id = static_cast(id); + Service::APT::SendParameter(message); + + started = false; + return RESULT_SUCCESS; +} + +void MiiSelector::Update() { +} + +} +} // namespace diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h new file mode 100644 index 0000000000..6a3e7c8ebf --- /dev/null +++ b/src/core/hle/applets/mii_selector.h @@ -0,0 +1,37 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/common_funcs.h" + +#include "core/hle/applets/applet.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/result.h" +#include "core/hle/service/apt/apt.h" + +namespace HLE { +namespace Applets { + +class MiiSelector final : public Applet { +public: + MiiSelector(Service::APT::AppletId id); + + ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; + ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; + void Update() override; + bool IsRunning() const override { return started; } + + /// TODO(Subv): Find out what this is actually used for. + /// It is believed that the application stores the current screen image here. + Kernel::SharedPtr framebuffer_memory; + + /// Whether this applet is currently running instead of the host application or not. + bool started; +}; + +} +} // namespace diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index ba66569b41..feb579778a 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -12,6 +12,7 @@ #include "core/hle/service/apt/apt_a.h" #include "core/hle/service/apt/apt_s.h" #include "core/hle/service/apt/apt_u.h" +#include "core/hle/service/fs/archive.h" #include "core/hle/hle.h" #include "core/hle/kernel/event.h" @@ -380,6 +381,24 @@ void StartLibraryApplet(Service::Interface* self) { cmd_buff[1] = applet->Start(parameter).raw; } +void GetAppletInfo(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + auto app_id = static_cast(cmd_buff[1]); + + if (auto applet = HLE::Applets::Applet::Get(app_id)) { + // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[4] = static_cast(Service::FS::MediaType::NAND); + cmd_buff[5] = 1; // Registered + cmd_buff[6] = 1; // Loaded + cmd_buff[7] = 0; // Applet Attributes + } else { + cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, + ErrorSummary::NotFound, ErrorLevel::Status).raw; + } + LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); +} + void Init() { AddService(new APT_A_Interface); AddService(new APT_S_Interface); diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 4a72b6b5c6..47a97c1a18 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -54,7 +54,7 @@ enum class AppletId : u32 { Notifications = 0x116, Miiverse = 0x117, SoftwareKeyboard1 = 0x201, - Ed = 0x202, + Ed1 = 0x202, PnoteApp = 0x204, SnoteApp = 0x205, Error = 0x206, @@ -64,6 +64,7 @@ enum class AppletId : u32 { Application = 0x300, AnyLibraryApplet = 0x400, SoftwareKeyboard2 = 0x401, + Ed2 = 0x402, }; /// Send a parameter to the currently-running application, which will read it via ReceiveParameter @@ -132,6 +133,20 @@ void Enable(Service::Interface* self); */ void GetAppletManInfo(Service::Interface* self); +/** + * APT::GetAppletInfo service function. + * Inputs: + * 1 : AppId + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-3 : Title ID + * 4 : Media Type + * 5 : Registered + * 6 : Loaded + * 7 : Attributes + */ +void GetAppletInfo(Service::Interface* self); + /** * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. * An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu uses this diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index 146bfd5959..2e9d1f4b4a 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -17,7 +17,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00030040, Enable, "Enable"}, {0x00040040, nullptr, "Finalize"}, {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, - {0x00060040, nullptr, "GetAppletInfo"}, + {0x00060040, GetAppletInfo, "GetAppletInfo"}, {0x00070000, nullptr, "GetLastSignaledAppletId"}, {0x00080000, nullptr, "CountRegisteredApplet"}, {0x00090040, IsRegistered, "IsRegistered"},