From 2a6ebadf66051362cdcf07d722f7e2d3cee14c82 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 25 May 2015 23:30:20 -0500
Subject: [PATCH] HLE/APT: Initial HLE support for applets.

Currently only the SWKBD is emulated, and there's currently no way to ask the user for input, so it always returns "Subv" as the text.
---
 src/core/CMakeLists.txt            |   4 +
 src/core/hle/applets/applet.cpp    |  40 +++++++++
 src/core/hle/applets/applet.h      |  53 +++++++++++
 src/core/hle/applets/swkbd.cpp     |  73 +++++++++++++++
 src/core/hle/applets/swkbd.h       |  67 ++++++++++++++
 src/core/hle/service/apt/apt.cpp   | 139 ++++++++++++++++++++++-------
 src/core/hle/service/apt/apt.h     |  49 +++++++++-
 src/core/hle/service/apt/apt_a.cpp |  31 ++++---
 src/core/hle/service/apt/apt_u.cpp |   4 +-
 9 files changed, 410 insertions(+), 50 deletions(-)
 create mode 100644 src/core/hle/applets/applet.cpp
 create mode 100644 src/core/hle/applets/applet.h
 create mode 100644 src/core/hle/applets/swkbd.cpp
 create mode 100644 src/core/hle/applets/swkbd.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4fcda48748..9b004440c2 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -25,6 +25,8 @@ set(SRCS
             file_sys/ivfc_archive.cpp
             hle/config_mem.cpp
             hle/hle.cpp
+            hle/applets/applet.cpp
+            hle/applets/swkbd.cpp
             hle/kernel/address_arbiter.cpp
             hle/kernel/event.cpp
             hle/kernel/kernel.cpp
@@ -150,6 +152,8 @@ set(HEADERS
             hle/config_mem.h
             hle/function_wrappers.h
             hle/hle.h
+            hle/applets/applet.h
+            hle/applets/swkbd.h
             hle/kernel/address_arbiter.h
             hle/kernel/event.h
             hle/kernel/kernel.h
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp
new file mode 100644
index 0000000000..1f447e5fc2
--- /dev/null
+++ b/src/core/hle/applets/applet.cpp
@@ -0,0 +1,40 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+
+#include "core/hle/applets/applet.h"
+#include "core/hle/applets/swkbd.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace HLE {
+namespace Applets {
+
+static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
+
+ResultCode Applet::Create(Service::APT::AppletId id) {
+    switch (id) {
+    case Service::APT::AppletId::SoftwareKeyboard1:
+    case Service::APT::AppletId::SoftwareKeyboard2:
+        applets[id] = std::make_shared<SoftwareKeyboard>(id);
+        break;
+    default:
+        // TODO(Subv): Find the right error code
+        return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
+    }
+
+    return RESULT_SUCCESS;
+}
+
+std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
+    auto itr = applets.find(id);
+    if (itr != applets.end())
+        return itr->second;
+    return nullptr;
+}
+
+}
+} // namespace
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
new file mode 100644
index 0000000000..221348d9c3
--- /dev/null
+++ b/src/core/hle/applets/applet.h
@@ -0,0 +1,53 @@
+// Copyright 2015 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 "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/apt/apt.h"
+
+namespace HLE {
+namespace Applets {
+
+class Applet {
+public:
+    virtual ~Applet() {};
+    Applet(Service::APT::AppletId id) : id(id) {};
+
+    /**
+     * Creates an instance of the Applet subclass identified by the parameter
+     * and stores it in a global map.
+     * @param id Id of the applet to create
+     * @returns ResultCode Whether the operation was successful or not
+     */
+    static ResultCode Create(Service::APT::AppletId id);
+
+    /**
+     * Retrieves the Applet instance identified by the specified id
+     * @param id Id of the Applet to retrieve
+     * @returns Requested Applet or nullptr if not found
+     */
+    static std::shared_ptr<Applet> Get(Service::APT::AppletId id);
+
+    /**
+     * Handles a parameter from the application
+     * @param parameter Parameter data to handle
+     * @returns ResultCode Whether the operation was successful or not
+     */
+    virtual ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) = 0;
+
+    /**
+     * Handles the Applet start event, triggered from the application
+     * @param parameter Parameter data to handle
+     * @returns ResultCode Whether the operation was successful or not
+     */
+    virtual ResultCode Start(Service::APT::AppletStartupParameter const& parameter) = 0;
+
+    Service::APT::AppletId id; ///< Id of this Applet
+};
+
+}
+} // namespace
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
new file mode 100644
index 0000000000..224aeb096b
--- /dev/null
+++ b/src/core/hle/applets/swkbd.cpp
@@ -0,0 +1,73 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+
+#include "core/hle/applets/swkbd.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace HLE {
+namespace Applets {
+
+SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {
+    // 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, "SoftwareKeyboard Memory");
+}
+
+ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
+    if (parameter.signal != static_cast<u32>(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<u32>(Service::APT::SignalType::LibAppFinished);
+    result.data = nullptr; 
+    result.buffer_size = 0;
+    result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
+    result.sender_id = static_cast<u32>(id);
+    result.object = framebuffer_memory;
+
+    Service::APT::SendParameter(result);
+    return RESULT_SUCCESS;
+}
+
+ResultCode SoftwareKeyboard::Start(Service::APT::AppletStartupParameter const& parameter) {
+    memcpy(&config, parameter.data, parameter.buffer_size);
+    text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
+
+    // TODO(Subv): Verify if this is the correct behavior
+    memset(text_memory->GetPointer(), 0, text_memory->size);
+
+    // TODO(Subv): Remove this hardcoded text
+    const wchar_t str[] = L"Subv";
+    memcpy(text_memory->GetPointer(), str, 4 * sizeof(wchar_t));
+    
+    // TODO(Subv): Ask for input and write it to the shared memory
+    // TODO(Subv): Find out what are the possible values for the return code,
+    // some games seem to check for a hardcoded 2
+    config.return_code = 2;
+    config.text_length = 5;
+    config.text_offset = 0;
+
+    Service::APT::MessageParameter message;
+    message.buffer_size = sizeof(SoftwareKeyboardConfig);
+    message.data = reinterpret_cast<u8*>(&config);
+    message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
+    message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
+    message.sender_id = static_cast<u32>(id);
+    Service::APT::SendParameter(message);
+
+    return RESULT_SUCCESS;
+}
+
+}
+} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
new file mode 100644
index 0000000000..d7199690c6
--- /dev/null
+++ b/src/core/hle/applets/swkbd.h
@@ -0,0 +1,67 @@
+// Copyright 2015 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 "core/hle/applets/applet.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/apt/apt.h"
+
+namespace HLE {
+namespace Applets {
+
+struct SoftwareKeyboardConfig {
+    INSERT_PADDING_WORDS(0x8);
+
+    u16 max_text_length; ///< Maximum length of the input text
+
+    INSERT_PADDING_BYTES(0x6E);
+
+    char16_t display_text[65]; ///< Text to display when asking the user for input
+
+    INSERT_PADDING_BYTES(0xE);
+
+    u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
+
+    INSERT_PADDING_WORDS(0x3);
+
+    u32 shared_memory_size; ///< Size of the SharedMemory
+
+    INSERT_PADDING_WORDS(0x1);
+
+    u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
+
+    INSERT_PADDING_WORDS(0x2);
+
+    u32 text_offset; ///< Offset in the SharedMemory where the output text starts
+    u16 text_length; ///< Length in characters of the output text
+
+    INSERT_PADDING_BYTES(0x2B6);
+};
+
+static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong");
+
+class SoftwareKeyboard : public Applet {
+public:
+    SoftwareKeyboard(Service::APT::AppletId id);
+    ~SoftwareKeyboard() {}
+
+    ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) override;
+    ResultCode Start(Service::APT::AppletStartupParameter const& parameter) override;
+
+    /// TODO(Subv): Find out what this is actually used for. 
+    // It is believed that the application stores the current screen image here.
+    Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
+
+    /// SharedMemory where the output text will be stored
+    Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
+    
+    /// Configuration of this instance of the SoftwareKeyboard, as received from the application
+    SoftwareKeyboardConfig config;
+};
+
+}
+} // namespace
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index b454a2709c..0c3889e837 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -6,6 +6,7 @@
 #include "common/file_util.h"
 #include "common/logging/log.h"
 
+#include "core/hle/applets/applet.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/apt/apt.h"
 #include "core/hle/service/apt/apt_a.h"
@@ -34,12 +35,21 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
 
 static Kernel::SharedPtr<Kernel::Mutex> lock;
 static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
-static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event
+static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
 
 static std::vector<u8> shared_font;
 
 static u32 cpu_percent; ///< CPU time available to the running application
 
+/// Parameter data to be returned in the next call to Glance/ReceiveParameter
+static MessageParameter next_parameter;
+
+void SendParameter(MessageParameter const& parameter) {
+    next_parameter = parameter;
+    // Signal the event to let the application know that a new parameter is ready to be read
+    parameter_event->Signal();
+}
+
 void Initialize(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 app_id = cmd_buff[1];
@@ -47,18 +57,18 @@ void Initialize(Service::Interface* self) {
 
     cmd_buff[2] = IPC::MoveHandleDesc(2);
     cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
-    cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom();
+    cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
 
     // TODO(bunnei): Check if these events are cleared every time Initialize is called.
     notification_event->Clear();
-    start_event->Clear();
+    parameter_event->Clear();
 
     ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
     lock->Release();
 
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 
-    LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
+    LOG_WARNING(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
 }
 
 void GetSharedFont(Service::Interface* self) {
@@ -85,9 +95,7 @@ void GetSharedFont(Service::Interface* self) {
 void NotifyToWait(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 app_id = cmd_buff[1];
-    // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
-    start_event->Signal();
-
+    
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
     LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
 }
@@ -112,6 +120,7 @@ void Enable(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    parameter_event->Signal(); // Let the application know that it has been started
     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
 }
 
@@ -121,8 +130,8 @@ void GetAppletManInfo(Service::Interface* self) {
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
     cmd_buff[2] = 0;
     cmd_buff[3] = 0;
-    cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID
-    cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly
+    cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
+    cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
 
     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
 }
@@ -131,7 +140,13 @@ void IsRegistered(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 app_id = cmd_buff[1];
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
-    cmd_buff[2] = 1; // Set to registered
+    /// TODO(Subv): It is currently unknown what this value (0x400) means,
+    /// but i believe it is used as a global "LibraryApplet" id, to verify if there's
+    /// any LibApplet currently running. This is not verified.
+    if (app_id != 0x400)
+        cmd_buff[2] = 1; // Set to registered
+    else
+        cmd_buff[2] = 0; // Set to not registered
     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
 }
 
@@ -145,50 +160,81 @@ void InquireNotification(Service::Interface* self) {
 
 void SendParameter(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
-    u32 src_app_id          = cmd_buff[1];
-    u32 dst_app_id          = cmd_buff[2];
-    u32 signal_type         = cmd_buff[3];
-    u32 buffer_size         = cmd_buff[4];
-    u32 value               = cmd_buff[5];
-    u32 handle              = cmd_buff[6];
-    u32 size                = cmd_buff[7];
-    u32 in_param_buffer_ptr = cmd_buff[8];
+    u32 src_app_id = cmd_buff[1];
+    u32 dst_app_id = cmd_buff[2];
+    u32 signal_type = cmd_buff[3];
+    u32 buffer_size = cmd_buff[4];
+    u32 value = cmd_buff[5];
+    u32 handle = cmd_buff[6];
+    u32 size = cmd_buff[7];
+    u32 buffer = cmd_buff[8];
 
-    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
+
+    if (dest_applet == nullptr) {
+        LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
+        return;
+    }
+
+    MessageParameter param;
+    param.buffer_size = buffer_size;
+    param.destination_id = dst_app_id;
+    param.sender_id = src_app_id;
+    param.object = Kernel::g_handle_table.GetGeneric(handle);
+    param.signal = signal_type;
+    param.data = Memory::GetPointer(buffer);
+
+    cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
 
     LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
                "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
-               src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr);
+               src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
 }
 
 void ReceiveParameter(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 app_id = cmd_buff[1];
     u32 buffer_size = cmd_buff[2];
+    VAddr buffer = cmd_buff[0x104 >> 2];
+
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
-    cmd_buff[2] = 0;
-    cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
-    cmd_buff[4] = 0x10; // Parameter buffer size (16)
-    cmd_buff[5] = 0;
+    cmd_buff[2] = next_parameter.sender_id;
+    cmd_buff[3] = next_parameter.signal; // Signal type
+    cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
+    cmd_buff[5] = 0x10;
     cmd_buff[6] = 0;
-    cmd_buff[7] = 0;
-    LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
+    if (next_parameter.object != nullptr)
+        cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
+    cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
+    cmd_buff[8] = buffer;
+
+    if (next_parameter.data)
+        memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
+
+    LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
 }
 
 void GlanceParameter(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
     u32 app_id = cmd_buff[1];
     u32 buffer_size = cmd_buff[2];
+    VAddr buffer = cmd_buff[0x104 >> 2];
 
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
-    cmd_buff[2] = 0;
-    cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
-    cmd_buff[4] = 0x10; // Parameter buffer size (16)
-    cmd_buff[5] = 0;
+    cmd_buff[2] = next_parameter.sender_id;
+    cmd_buff[3] = next_parameter.signal; // Signal type
+    cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
+    cmd_buff[5] = 0x10;
     cmd_buff[6] = 0;
-    cmd_buff[7] = 0;
+    if (next_parameter.object != nullptr)
+        cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
+    cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
+    cmd_buff[8] = buffer;
 
-    LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
+    if (next_parameter.data)
+        memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
+
+    LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
 }
 
 void CancelParameter(Service::Interface* self) {
@@ -281,6 +327,28 @@ void GetAppCpuTimeLimit(Service::Interface* self) {
     LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
 }
 
+void PrepareToStartLibraryApplet(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    cmd_buff[1] = HLE::Applets::Applet::Create(static_cast<AppletId>(cmd_buff[1])).raw;
+}
+
+void StartLibraryApplet(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(static_cast<AppletId>(cmd_buff[1]));
+    
+    if (applet == nullptr) {
+        cmd_buff[1] = -1; // TODO(Subv): Find the right error code
+        return;
+    }
+
+    AppletStartupParameter parameter;
+    parameter.buffer_size = cmd_buff[2];
+    parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
+    parameter.data = Memory::GetPointer(cmd_buff[6]);
+
+    cmd_buff[1] = applet->Start(parameter).raw;
+}
+
 void Init() {
     AddService(new APT_A_Interface);
     AddService(new APT_S_Interface);
@@ -318,7 +386,10 @@ void Init() {
 
     // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
     notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
-    start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
+    parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
+
+    next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted);
+    next_parameter.destination_id = 0x300;
 }
 
 void Shutdown() {
@@ -326,7 +397,7 @@ void Shutdown() {
     shared_font_mem = nullptr;
     lock = nullptr;
     notification_event = nullptr;
-    start_event = nullptr;
+    parameter_event = nullptr;
 }
 
 } // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a03e1712a3..510193cc80 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -11,6 +11,23 @@
 namespace Service {
 namespace APT {
 
+/// Holds information about the parameters used in Send/Glance/ReceiveParameter
+struct MessageParameter {
+    u32 sender_id = 0;
+    u32 destination_id = 0;
+    u32 signal = 0;
+    u32 buffer_size = 0;
+    Kernel::SharedPtr<Kernel::Object> object = nullptr;
+    u8* data = nullptr;
+};
+
+/// Holds information about the parameters used in StartLibraryApplet
+struct AppletStartupParameter {
+    u32 buffer_size = 0;
+    Kernel::SharedPtr<Kernel::Object> object = nullptr;
+    u8* data = nullptr;
+};
+
 /// Signals used by APT functions
 enum class SignalType : u32 {
     None              = 0x0,
@@ -23,7 +40,7 @@ enum class SignalType : u32 {
 };
 
 /// App Id's used by APT functions
-enum class AppID : u32 {
+enum class AppletId : u32 {
     HomeMenu           = 0x101,
     AlternateMenu      = 0x103,
     Camera             = 0x110,
@@ -45,6 +62,9 @@ enum class AppID : u32 {
     SoftwareKeyboard2  = 0x401,
 };
 
+/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
+void SendParameter(MessageParameter const& parameter);
+
 /**
  * APT::Initialize service function
  * Service function that initializes the APT process for the running application
@@ -249,6 +269,33 @@ void SetAppCpuTimeLimit(Service::Interface* self);
  */
 void GetAppCpuTimeLimit(Service::Interface* self);
 
+/**
+ * APT::PrepareToStartLibraryApplet service function
+ *  Inputs:
+ *      0 : Command header [0x00180040]
+ *      1 : Id of the applet to start
+ *  Outputs:
+ *      0 : Return header
+ *      1 : Result of function, 0 on success, otherwise error code
+ */
+void PrepareToStartLibraryApplet(Service::Interface* self);
+
+/**
+ * APT::StartLibraryApplet service function
+ *  Inputs:
+ *      0 : Command header [0x001E0084]
+ *      1 : Id of the applet to start
+ *      2 : Buffer size
+ *      3 : Always 0?
+ *      4 : Handle passed to the applet
+ *      5 : (Size << 14) | 2
+ *      6 : Input buffer virtual address
+ *  Outputs:
+ *      0 : Return header
+ *      1 : Result of function, 0 on success, otherwise error code
+ */
+void StartLibraryApplet(Service::Interface* self);
+
 /// Initialize the APT service
 void Init();
 
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 8649342458..88de339f97 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -10,19 +10,24 @@ namespace Service {
 namespace APT {
 
 const Interface::FunctionInfo FunctionTable[] = {
-    {0x00010040, GetLockHandle,      "GetLockHandle?"},
-    {0x00020080, Initialize,         "Initialize?"},
-    {0x00030040, Enable,             "Enable?"},
-    {0x00040040, nullptr,            "Finalize?"},
-    {0x00050040, nullptr,            "GetAppletManInfo?"},
-    {0x00060040, nullptr,            "GetAppletInfo?"},
-    {0x000D0080, ReceiveParameter,   "ReceiveParameter?"},
-    {0x000E0080, GlanceParameter,    "GlanceParameter?"},
-    {0x003B0040, nullptr,            "CancelLibraryApplet?"},
-    {0x00430040, NotifyToWait,       "NotifyToWait?"},
-    {0x00440000, GetSharedFont,      "GetSharedFont?"},
-    {0x004B00C2, AppletUtility,      "AppletUtility?"},
-    {0x00550040, nullptr,            "WriteInputToNsState?"},
+    {0x00010040, GetLockHandle,                "GetLockHandle?"},
+    {0x00020080, Initialize,                   "Initialize?"},
+    {0x00030040, Enable,                       "Enable?"},
+    {0x00040040, nullptr,                      "Finalize?"},
+    {0x00050040, nullptr,                      "GetAppletManInfo?"},
+    {0x00060040, nullptr,                      "GetAppletInfo?"},
+    {0x00090040, IsRegistered,                 "IsRegistered"},
+    {0x000C0104, SendParameter,                "SendParameter"},
+    {0x000D0080, ReceiveParameter,             "ReceiveParameter"},
+    {0x000E0080, GlanceParameter,              "GlanceParameter"},
+    {0x000F0100, CancelParameter,              "CancelParameter"},
+    {0x00180040, PrepareToStartLibraryApplet,  "PrepareToStartLibraryApplet"},
+    {0x001E0084, StartLibraryApplet,           "StartLibraryApplet"},
+    {0x003B0040, nullptr,                      "CancelLibraryApplet?"},
+    {0x00430040, NotifyToWait,                 "NotifyToWait?"},
+    {0x00440000, GetSharedFont,                "GetSharedFont?"},
+    {0x004B00C2, AppletUtility,                "AppletUtility?"},
+    {0x00550040, nullptr,                      "WriteInputToNsState?"},
 };
 
 APT_A_Interface::APT_A_Interface() {
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index d006b59308..b724cd72bd 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -35,13 +35,13 @@ const Interface::FunctionInfo FunctionTable[] = {
     {0x00150140, nullptr,                         "PrepareToStartApplication"},
     {0x00160040, nullptr,                         "PreloadLibraryApplet"},
     {0x00170040, nullptr,                         "FinishPreloadingLibraryApplet"},
-    {0x00180040, nullptr,                         "PrepareToStartLibraryApplet"},
+    {0x00180040, PrepareToStartLibraryApplet,     "PrepareToStartLibraryApplet"},
     {0x00190040, nullptr,                         "PrepareToStartSystemApplet"},
     {0x001A0000, nullptr,                         "PrepareToStartNewestHomeMenu"},
     {0x001B00C4, nullptr,                         "StartApplication"},
     {0x001C0000, nullptr,                         "WakeupApplication"},
     {0x001D0000, nullptr,                         "CancelApplication"},
-    {0x001E0084, nullptr,                         "StartLibraryApplet"},
+    {0x001E0084, StartLibraryApplet,              "StartLibraryApplet"},
     {0x001F0084, nullptr,                         "StartSystemApplet"},
     {0x00200044, nullptr,                         "StartNewestHomeMenu"},
     {0x00210000, nullptr,                         "OrderToCloseApplication"},