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.
This commit is contained in:
parent
b0d72e3de1
commit
2a6ebadf66
|
@ -25,6 +25,8 @@ set(SRCS
|
||||||
file_sys/ivfc_archive.cpp
|
file_sys/ivfc_archive.cpp
|
||||||
hle/config_mem.cpp
|
hle/config_mem.cpp
|
||||||
hle/hle.cpp
|
hle/hle.cpp
|
||||||
|
hle/applets/applet.cpp
|
||||||
|
hle/applets/swkbd.cpp
|
||||||
hle/kernel/address_arbiter.cpp
|
hle/kernel/address_arbiter.cpp
|
||||||
hle/kernel/event.cpp
|
hle/kernel/event.cpp
|
||||||
hle/kernel/kernel.cpp
|
hle/kernel/kernel.cpp
|
||||||
|
@ -150,6 +152,8 @@ set(HEADERS
|
||||||
hle/config_mem.h
|
hle/config_mem.h
|
||||||
hle/function_wrappers.h
|
hle/function_wrappers.h
|
||||||
hle/hle.h
|
hle/hle.h
|
||||||
|
hle/applets/applet.h
|
||||||
|
hle/applets/swkbd.h
|
||||||
hle/kernel/address_arbiter.h
|
hle/kernel/address_arbiter.h
|
||||||
hle/kernel/event.h
|
hle/kernel/event.h
|
||||||
hle/kernel/kernel.h
|
hle/kernel/kernel.h
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -6,6 +6,7 @@
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
|
#include "core/hle/applets/applet.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/hle/service/apt/apt.h"
|
#include "core/hle/service/apt/apt.h"
|
||||||
#include "core/hle/service/apt/apt_a.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::Mutex> lock;
|
||||||
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
|
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 std::vector<u8> shared_font;
|
||||||
|
|
||||||
static u32 cpu_percent; ///< CPU time available to the running application
|
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) {
|
void Initialize(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
u32 app_id = cmd_buff[1];
|
u32 app_id = cmd_buff[1];
|
||||||
|
@ -47,18 +57,18 @@ void Initialize(Service::Interface* self) {
|
||||||
|
|
||||||
cmd_buff[2] = IPC::MoveHandleDesc(2);
|
cmd_buff[2] = IPC::MoveHandleDesc(2);
|
||||||
cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
|
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.
|
// TODO(bunnei): Check if these events are cleared every time Initialize is called.
|
||||||
notification_event->Clear();
|
notification_event->Clear();
|
||||||
start_event->Clear();
|
parameter_event->Clear();
|
||||||
|
|
||||||
ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
|
ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
|
||||||
lock->Release();
|
lock->Release();
|
||||||
|
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
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) {
|
void GetSharedFont(Service::Interface* self) {
|
||||||
|
@ -85,9 +95,7 @@ void GetSharedFont(Service::Interface* self) {
|
||||||
void NotifyToWait(Service::Interface* self) {
|
void NotifyToWait(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
u32 app_id = cmd_buff[1];
|
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
|
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||||
LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
|
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* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
|
u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
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);
|
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[1] = RESULT_SUCCESS.raw; // No error
|
||||||
cmd_buff[2] = 0;
|
cmd_buff[2] = 0;
|
||||||
cmd_buff[3] = 0;
|
cmd_buff[3] = 0;
|
||||||
cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID
|
cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
|
||||||
cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly
|
cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
|
||||||
|
|
||||||
LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
|
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* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
u32 app_id = cmd_buff[1];
|
u32 app_id = cmd_buff[1];
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
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);
|
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) {
|
void SendParameter(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
u32 src_app_id = cmd_buff[1];
|
u32 src_app_id = cmd_buff[1];
|
||||||
u32 dst_app_id = cmd_buff[2];
|
u32 dst_app_id = cmd_buff[2];
|
||||||
u32 signal_type = cmd_buff[3];
|
u32 signal_type = cmd_buff[3];
|
||||||
u32 buffer_size = cmd_buff[4];
|
u32 buffer_size = cmd_buff[4];
|
||||||
u32 value = cmd_buff[5];
|
u32 value = cmd_buff[5];
|
||||||
u32 handle = cmd_buff[6];
|
u32 handle = cmd_buff[6];
|
||||||
u32 size = cmd_buff[7];
|
u32 size = cmd_buff[7];
|
||||||
u32 in_param_buffer_ptr = cmd_buff[8];
|
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,"
|
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",
|
"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) {
|
void ReceiveParameter(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
u32 app_id = cmd_buff[1];
|
u32 app_id = cmd_buff[1];
|
||||||
u32 buffer_size = cmd_buff[2];
|
u32 buffer_size = cmd_buff[2];
|
||||||
|
VAddr buffer = cmd_buff[0x104 >> 2];
|
||||||
|
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||||
cmd_buff[2] = 0;
|
cmd_buff[2] = next_parameter.sender_id;
|
||||||
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
|
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||||
cmd_buff[4] = 0x10; // Parameter buffer size (16)
|
cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
|
||||||
cmd_buff[5] = 0;
|
cmd_buff[5] = 0x10;
|
||||||
cmd_buff[6] = 0;
|
cmd_buff[6] = 0;
|
||||||
cmd_buff[7] = 0;
|
if (next_parameter.object != nullptr)
|
||||||
LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
|
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) {
|
void GlanceParameter(Service::Interface* self) {
|
||||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
u32 app_id = cmd_buff[1];
|
u32 app_id = cmd_buff[1];
|
||||||
u32 buffer_size = cmd_buff[2];
|
u32 buffer_size = cmd_buff[2];
|
||||||
|
VAddr buffer = cmd_buff[0x104 >> 2];
|
||||||
|
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||||
cmd_buff[2] = 0;
|
cmd_buff[2] = next_parameter.sender_id;
|
||||||
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
|
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||||
cmd_buff[4] = 0x10; // Parameter buffer size (16)
|
cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
|
||||||
cmd_buff[5] = 0;
|
cmd_buff[5] = 0x10;
|
||||||
cmd_buff[6] = 0;
|
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) {
|
void CancelParameter(Service::Interface* self) {
|
||||||
|
@ -281,6 +327,28 @@ void GetAppCpuTimeLimit(Service::Interface* self) {
|
||||||
LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
|
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() {
|
void Init() {
|
||||||
AddService(new APT_A_Interface);
|
AddService(new APT_A_Interface);
|
||||||
AddService(new APT_S_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.
|
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
|
||||||
notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
|
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() {
|
void Shutdown() {
|
||||||
|
@ -326,7 +397,7 @@ void Shutdown() {
|
||||||
shared_font_mem = nullptr;
|
shared_font_mem = nullptr;
|
||||||
lock = nullptr;
|
lock = nullptr;
|
||||||
notification_event = nullptr;
|
notification_event = nullptr;
|
||||||
start_event = nullptr;
|
parameter_event = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace APT
|
} // namespace APT
|
||||||
|
|
|
@ -11,6 +11,23 @@
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace APT {
|
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
|
/// Signals used by APT functions
|
||||||
enum class SignalType : u32 {
|
enum class SignalType : u32 {
|
||||||
None = 0x0,
|
None = 0x0,
|
||||||
|
@ -23,7 +40,7 @@ enum class SignalType : u32 {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// App Id's used by APT functions
|
/// App Id's used by APT functions
|
||||||
enum class AppID : u32 {
|
enum class AppletId : u32 {
|
||||||
HomeMenu = 0x101,
|
HomeMenu = 0x101,
|
||||||
AlternateMenu = 0x103,
|
AlternateMenu = 0x103,
|
||||||
Camera = 0x110,
|
Camera = 0x110,
|
||||||
|
@ -45,6 +62,9 @@ enum class AppID : u32 {
|
||||||
SoftwareKeyboard2 = 0x401,
|
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
|
* APT::Initialize service function
|
||||||
* Service function that initializes the APT process for the running application
|
* 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);
|
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
|
/// Initialize the APT service
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
|
|
|
@ -10,19 +10,24 @@ namespace Service {
|
||||||
namespace APT {
|
namespace APT {
|
||||||
|
|
||||||
const Interface::FunctionInfo FunctionTable[] = {
|
const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x00010040, GetLockHandle, "GetLockHandle?"},
|
{0x00010040, GetLockHandle, "GetLockHandle?"},
|
||||||
{0x00020080, Initialize, "Initialize?"},
|
{0x00020080, Initialize, "Initialize?"},
|
||||||
{0x00030040, Enable, "Enable?"},
|
{0x00030040, Enable, "Enable?"},
|
||||||
{0x00040040, nullptr, "Finalize?"},
|
{0x00040040, nullptr, "Finalize?"},
|
||||||
{0x00050040, nullptr, "GetAppletManInfo?"},
|
{0x00050040, nullptr, "GetAppletManInfo?"},
|
||||||
{0x00060040, nullptr, "GetAppletInfo?"},
|
{0x00060040, nullptr, "GetAppletInfo?"},
|
||||||
{0x000D0080, ReceiveParameter, "ReceiveParameter?"},
|
{0x00090040, IsRegistered, "IsRegistered"},
|
||||||
{0x000E0080, GlanceParameter, "GlanceParameter?"},
|
{0x000C0104, SendParameter, "SendParameter"},
|
||||||
{0x003B0040, nullptr, "CancelLibraryApplet?"},
|
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||||
{0x00430040, NotifyToWait, "NotifyToWait?"},
|
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||||
{0x00440000, GetSharedFont, "GetSharedFont?"},
|
{0x000F0100, CancelParameter, "CancelParameter"},
|
||||||
{0x004B00C2, AppletUtility, "AppletUtility?"},
|
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
|
||||||
{0x00550040, nullptr, "WriteInputToNsState?"},
|
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
|
||||||
|
{0x003B0040, nullptr, "CancelLibraryApplet?"},
|
||||||
|
{0x00430040, NotifyToWait, "NotifyToWait?"},
|
||||||
|
{0x00440000, GetSharedFont, "GetSharedFont?"},
|
||||||
|
{0x004B00C2, AppletUtility, "AppletUtility?"},
|
||||||
|
{0x00550040, nullptr, "WriteInputToNsState?"},
|
||||||
};
|
};
|
||||||
|
|
||||||
APT_A_Interface::APT_A_Interface() {
|
APT_A_Interface::APT_A_Interface() {
|
||||||
|
|
|
@ -35,13 +35,13 @@ const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x00150140, nullptr, "PrepareToStartApplication"},
|
{0x00150140, nullptr, "PrepareToStartApplication"},
|
||||||
{0x00160040, nullptr, "PreloadLibraryApplet"},
|
{0x00160040, nullptr, "PreloadLibraryApplet"},
|
||||||
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
|
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
|
||||||
{0x00180040, nullptr, "PrepareToStartLibraryApplet"},
|
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
|
||||||
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
|
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
|
||||||
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
|
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
|
||||||
{0x001B00C4, nullptr, "StartApplication"},
|
{0x001B00C4, nullptr, "StartApplication"},
|
||||||
{0x001C0000, nullptr, "WakeupApplication"},
|
{0x001C0000, nullptr, "WakeupApplication"},
|
||||||
{0x001D0000, nullptr, "CancelApplication"},
|
{0x001D0000, nullptr, "CancelApplication"},
|
||||||
{0x001E0084, nullptr, "StartLibraryApplet"},
|
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
|
||||||
{0x001F0084, nullptr, "StartSystemApplet"},
|
{0x001F0084, nullptr, "StartSystemApplet"},
|
||||||
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
||||||
{0x00210000, nullptr, "OrderToCloseApplication"},
|
{0x00210000, nullptr, "OrderToCloseApplication"},
|
||||||
|
|
Reference in New Issue