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.pull/15/head
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"},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue