summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Subv2015-05-25 23:30:20 -0500
committerGravatar Subv2015-07-11 21:47:22 -0500
commit2a6ebadf66051362cdcf07d722f7e2d3cee14c82 (patch)
treef016b2ee81df95aabccc426762c42073d645803c /src
parentMerge pull request #914 from yuriks/bitfield-mask (diff)
downloadyuzu-2a6ebadf66051362cdcf07d722f7e2d3cee14c82.tar.gz
yuzu-2a6ebadf66051362cdcf07d722f7e2d3cee14c82.tar.xz
yuzu-2a6ebadf66051362cdcf07d722f7e2d3cee14c82.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/hle/applets/applet.cpp40
-rw-r--r--src/core/hle/applets/applet.h53
-rw-r--r--src/core/hle/applets/swkbd.cpp73
-rw-r--r--src/core/hle/applets/swkbd.h67
-rw-r--r--src/core/hle/service/apt/apt.cpp139
-rw-r--r--src/core/hle/service/apt/apt.h49
-rw-r--r--src/core/hle/service/apt/apt_a.cpp31
-rw-r--r--src/core/hle/service/apt/apt_u.cpp4
9 files changed, 410 insertions, 50 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4fcda4874..9b004440c 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -25,6 +25,8 @@ set(SRCS
25 file_sys/ivfc_archive.cpp 25 file_sys/ivfc_archive.cpp
26 hle/config_mem.cpp 26 hle/config_mem.cpp
27 hle/hle.cpp 27 hle/hle.cpp
28 hle/applets/applet.cpp
29 hle/applets/swkbd.cpp
28 hle/kernel/address_arbiter.cpp 30 hle/kernel/address_arbiter.cpp
29 hle/kernel/event.cpp 31 hle/kernel/event.cpp
30 hle/kernel/kernel.cpp 32 hle/kernel/kernel.cpp
@@ -150,6 +152,8 @@ set(HEADERS
150 hle/config_mem.h 152 hle/config_mem.h
151 hle/function_wrappers.h 153 hle/function_wrappers.h
152 hle/hle.h 154 hle/hle.h
155 hle/applets/applet.h
156 hle/applets/swkbd.h
153 hle/kernel/address_arbiter.h 157 hle/kernel/address_arbiter.h
154 hle/kernel/event.h 158 hle/kernel/event.h
155 hle/kernel/kernel.h 159 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 000000000..1f447e5fc
--- /dev/null
+++ b/src/core/hle/applets/applet.cpp
@@ -0,0 +1,40 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/logging/log.h"
7
8#include "core/hle/applets/applet.h"
9#include "core/hle/applets/swkbd.h"
10
11////////////////////////////////////////////////////////////////////////////////////////////////////
12
13namespace HLE {
14namespace Applets {
15
16static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
17
18ResultCode Applet::Create(Service::APT::AppletId id) {
19 switch (id) {
20 case Service::APT::AppletId::SoftwareKeyboard1:
21 case Service::APT::AppletId::SoftwareKeyboard2:
22 applets[id] = std::make_shared<SoftwareKeyboard>(id);
23 break;
24 default:
25 // TODO(Subv): Find the right error code
26 return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
27 }
28
29 return RESULT_SUCCESS;
30}
31
32std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
33 auto itr = applets.find(id);
34 if (itr != applets.end())
35 return itr->second;
36 return nullptr;
37}
38
39}
40} // namespace
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
new file mode 100644
index 000000000..221348d9c
--- /dev/null
+++ b/src/core/hle/applets/applet.h
@@ -0,0 +1,53 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/shared_memory.h"
10#include "core/hle/service/apt/apt.h"
11
12namespace HLE {
13namespace Applets {
14
15class Applet {
16public:
17 virtual ~Applet() {};
18 Applet(Service::APT::AppletId id) : id(id) {};
19
20 /**
21 * Creates an instance of the Applet subclass identified by the parameter
22 * and stores it in a global map.
23 * @param id Id of the applet to create
24 * @returns ResultCode Whether the operation was successful or not
25 */
26 static ResultCode Create(Service::APT::AppletId id);
27
28 /**
29 * Retrieves the Applet instance identified by the specified id
30 * @param id Id of the Applet to retrieve
31 * @returns Requested Applet or nullptr if not found
32 */
33 static std::shared_ptr<Applet> Get(Service::APT::AppletId id);
34
35 /**
36 * Handles a parameter from the application
37 * @param parameter Parameter data to handle
38 * @returns ResultCode Whether the operation was successful or not
39 */
40 virtual ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) = 0;
41
42 /**
43 * Handles the Applet start event, triggered from the application
44 * @param parameter Parameter data to handle
45 * @returns ResultCode Whether the operation was successful or not
46 */
47 virtual ResultCode Start(Service::APT::AppletStartupParameter const& parameter) = 0;
48
49 Service::APT::AppletId id; ///< Id of this Applet
50};
51
52}
53} // namespace
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
new file mode 100644
index 000000000..224aeb096
--- /dev/null
+++ b/src/core/hle/applets/swkbd.cpp
@@ -0,0 +1,73 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/logging/log.h"
7
8#include "core/hle/applets/swkbd.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11
12namespace HLE {
13namespace Applets {
14
15SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {
16 // Create the SharedMemory that will hold the framebuffer data
17 // TODO(Subv): What size should we use here?
18 using Kernel::MemoryPermission;
19 framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
20}
21
22ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
23 if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) {
24 LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
25 UNIMPLEMENTED();
26 // TODO(Subv): Find the right error code
27 return ResultCode(-1);
28 }
29
30 Service::APT::MessageParameter result;
31 // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
32 result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
33 result.data = nullptr;
34 result.buffer_size = 0;
35 result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
36 result.sender_id = static_cast<u32>(id);
37 result.object = framebuffer_memory;
38
39 Service::APT::SendParameter(result);
40 return RESULT_SUCCESS;
41}
42
43ResultCode SoftwareKeyboard::Start(Service::APT::AppletStartupParameter const& parameter) {
44 memcpy(&config, parameter.data, parameter.buffer_size);
45 text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
46
47 // TODO(Subv): Verify if this is the correct behavior
48 memset(text_memory->GetPointer(), 0, text_memory->size);
49
50 // TODO(Subv): Remove this hardcoded text
51 const wchar_t str[] = L"Subv";
52 memcpy(text_memory->GetPointer(), str, 4 * sizeof(wchar_t));
53
54 // TODO(Subv): Ask for input and write it to the shared memory
55 // TODO(Subv): Find out what are the possible values for the return code,
56 // some games seem to check for a hardcoded 2
57 config.return_code = 2;
58 config.text_length = 5;
59 config.text_offset = 0;
60
61 Service::APT::MessageParameter message;
62 message.buffer_size = sizeof(SoftwareKeyboardConfig);
63 message.data = reinterpret_cast<u8*>(&config);
64 message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
65 message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
66 message.sender_id = static_cast<u32>(id);
67 Service::APT::SendParameter(message);
68
69 return RESULT_SUCCESS;
70}
71
72}
73} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
new file mode 100644
index 000000000..d7199690c
--- /dev/null
+++ b/src/core/hle/applets/swkbd.h
@@ -0,0 +1,67 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/hle/applets/applet.h"
9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/shared_memory.h"
11#include "core/hle/service/apt/apt.h"
12
13namespace HLE {
14namespace Applets {
15
16struct SoftwareKeyboardConfig {
17 INSERT_PADDING_WORDS(0x8);
18
19 u16 max_text_length; ///< Maximum length of the input text
20
21 INSERT_PADDING_BYTES(0x6E);
22
23 char16_t display_text[65]; ///< Text to display when asking the user for input
24
25 INSERT_PADDING_BYTES(0xE);
26
27 u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
28
29 INSERT_PADDING_WORDS(0x3);
30
31 u32 shared_memory_size; ///< Size of the SharedMemory
32
33 INSERT_PADDING_WORDS(0x1);
34
35 u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
36
37 INSERT_PADDING_WORDS(0x2);
38
39 u32 text_offset; ///< Offset in the SharedMemory where the output text starts
40 u16 text_length; ///< Length in characters of the output text
41
42 INSERT_PADDING_BYTES(0x2B6);
43};
44
45static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong");
46
47class SoftwareKeyboard : public Applet {
48public:
49 SoftwareKeyboard(Service::APT::AppletId id);
50 ~SoftwareKeyboard() {}
51
52 ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) override;
53 ResultCode Start(Service::APT::AppletStartupParameter const& parameter) override;
54
55 /// TODO(Subv): Find out what this is actually used for.
56 // It is believed that the application stores the current screen image here.
57 Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
58
59 /// SharedMemory where the output text will be stored
60 Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
61
62 /// Configuration of this instance of the SoftwareKeyboard, as received from the application
63 SoftwareKeyboardConfig config;
64};
65
66}
67} // namespace
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index b454a2709..0c3889e83 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -6,6 +6,7 @@
6#include "common/file_util.h" 6#include "common/file_util.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8 8
9#include "core/hle/applets/applet.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
10#include "core/hle/service/apt/apt.h" 11#include "core/hle/service/apt/apt.h"
11#include "core/hle/service/apt/apt_a.h" 12#include "core/hle/service/apt/apt_a.h"
@@ -34,12 +35,21 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
34 35
35static Kernel::SharedPtr<Kernel::Mutex> lock; 36static Kernel::SharedPtr<Kernel::Mutex> lock;
36static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event 37static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
37static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event 38static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
38 39
39static std::vector<u8> shared_font; 40static std::vector<u8> shared_font;
40 41
41static u32 cpu_percent; ///< CPU time available to the running application 42static u32 cpu_percent; ///< CPU time available to the running application
42 43
44/// Parameter data to be returned in the next call to Glance/ReceiveParameter
45static MessageParameter next_parameter;
46
47void SendParameter(MessageParameter const& parameter) {
48 next_parameter = parameter;
49 // Signal the event to let the application know that a new parameter is ready to be read
50 parameter_event->Signal();
51}
52
43void Initialize(Service::Interface* self) { 53void Initialize(Service::Interface* self) {
44 u32* cmd_buff = Kernel::GetCommandBuffer(); 54 u32* cmd_buff = Kernel::GetCommandBuffer();
45 u32 app_id = cmd_buff[1]; 55 u32 app_id = cmd_buff[1];
@@ -47,18 +57,18 @@ void Initialize(Service::Interface* self) {
47 57
48 cmd_buff[2] = IPC::MoveHandleDesc(2); 58 cmd_buff[2] = IPC::MoveHandleDesc(2);
49 cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); 59 cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
50 cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom(); 60 cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
51 61
52 // TODO(bunnei): Check if these events are cleared every time Initialize is called. 62 // TODO(bunnei): Check if these events are cleared every time Initialize is called.
53 notification_event->Clear(); 63 notification_event->Clear();
54 start_event->Clear(); 64 parameter_event->Clear();
55 65
56 ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); 66 ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
57 lock->Release(); 67 lock->Release();
58 68
59 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 69 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
60 70
61 LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); 71 LOG_WARNING(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
62} 72}
63 73
64void GetSharedFont(Service::Interface* self) { 74void GetSharedFont(Service::Interface* self) {
@@ -85,9 +95,7 @@ void GetSharedFont(Service::Interface* self) {
85void NotifyToWait(Service::Interface* self) { 95void NotifyToWait(Service::Interface* self) {
86 u32* cmd_buff = Kernel::GetCommandBuffer(); 96 u32* cmd_buff = Kernel::GetCommandBuffer();
87 u32 app_id = cmd_buff[1]; 97 u32 app_id = cmd_buff[1];
88 // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further. 98
89 start_event->Signal();
90
91 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 99 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
92 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); 100 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
93} 101}
@@ -112,6 +120,7 @@ void Enable(Service::Interface* self) {
112 u32* cmd_buff = Kernel::GetCommandBuffer(); 120 u32* cmd_buff = Kernel::GetCommandBuffer();
113 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? 121 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
114 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 122 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
123 parameter_event->Signal(); // Let the application know that it has been started
115 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 124 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
116} 125}
117 126
@@ -121,8 +130,8 @@ void GetAppletManInfo(Service::Interface* self) {
121 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 130 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
122 cmd_buff[2] = 0; 131 cmd_buff[2] = 0;
123 cmd_buff[3] = 0; 132 cmd_buff[3] = 0;
124 cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID 133 cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
125 cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly 134 cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
126 135
127 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 136 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
128} 137}
@@ -131,7 +140,13 @@ void IsRegistered(Service::Interface* self) {
131 u32* cmd_buff = Kernel::GetCommandBuffer(); 140 u32* cmd_buff = Kernel::GetCommandBuffer();
132 u32 app_id = cmd_buff[1]; 141 u32 app_id = cmd_buff[1];
133 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 142 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
134 cmd_buff[2] = 1; // Set to registered 143 /// TODO(Subv): It is currently unknown what this value (0x400) means,
144 /// but i believe it is used as a global "LibraryApplet" id, to verify if there's
145 /// any LibApplet currently running. This is not verified.
146 if (app_id != 0x400)
147 cmd_buff[2] = 1; // Set to registered
148 else
149 cmd_buff[2] = 0; // Set to not registered
135 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); 150 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
136} 151}
137 152
@@ -145,50 +160,81 @@ void InquireNotification(Service::Interface* self) {
145 160
146void SendParameter(Service::Interface* self) { 161void SendParameter(Service::Interface* self) {
147 u32* cmd_buff = Kernel::GetCommandBuffer(); 162 u32* cmd_buff = Kernel::GetCommandBuffer();
148 u32 src_app_id = cmd_buff[1]; 163 u32 src_app_id = cmd_buff[1];
149 u32 dst_app_id = cmd_buff[2]; 164 u32 dst_app_id = cmd_buff[2];
150 u32 signal_type = cmd_buff[3]; 165 u32 signal_type = cmd_buff[3];
151 u32 buffer_size = cmd_buff[4]; 166 u32 buffer_size = cmd_buff[4];
152 u32 value = cmd_buff[5]; 167 u32 value = cmd_buff[5];
153 u32 handle = cmd_buff[6]; 168 u32 handle = cmd_buff[6];
154 u32 size = cmd_buff[7]; 169 u32 size = cmd_buff[7];
155 u32 in_param_buffer_ptr = cmd_buff[8]; 170 u32 buffer = cmd_buff[8];
171
172 std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
173
174 if (dest_applet == nullptr) {
175 LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
176 return;
177 }
156 178
157 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 179 MessageParameter param;
180 param.buffer_size = buffer_size;
181 param.destination_id = dst_app_id;
182 param.sender_id = src_app_id;
183 param.object = Kernel::g_handle_table.GetGeneric(handle);
184 param.signal = signal_type;
185 param.data = Memory::GetPointer(buffer);
186
187 cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
158 188
159 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," 189 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
160 "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", 190 "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
161 src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); 191 src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
162} 192}
163 193
164void ReceiveParameter(Service::Interface* self) { 194void ReceiveParameter(Service::Interface* self) {
165 u32* cmd_buff = Kernel::GetCommandBuffer(); 195 u32* cmd_buff = Kernel::GetCommandBuffer();
166 u32 app_id = cmd_buff[1]; 196 u32 app_id = cmd_buff[1];
167 u32 buffer_size = cmd_buff[2]; 197 u32 buffer_size = cmd_buff[2];
198 VAddr buffer = cmd_buff[0x104 >> 2];
199
168 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 200 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
169 cmd_buff[2] = 0; 201 cmd_buff[2] = next_parameter.sender_id;
170 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type 202 cmd_buff[3] = next_parameter.signal; // Signal type
171 cmd_buff[4] = 0x10; // Parameter buffer size (16) 203 cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
172 cmd_buff[5] = 0; 204 cmd_buff[5] = 0x10;
173 cmd_buff[6] = 0; 205 cmd_buff[6] = 0;
174 cmd_buff[7] = 0; 206 if (next_parameter.object != nullptr)
175 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 207 cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
208 cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
209 cmd_buff[8] = buffer;
210
211 if (next_parameter.data)
212 memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
213
214 LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
176} 215}
177 216
178void GlanceParameter(Service::Interface* self) { 217void GlanceParameter(Service::Interface* self) {
179 u32* cmd_buff = Kernel::GetCommandBuffer(); 218 u32* cmd_buff = Kernel::GetCommandBuffer();
180 u32 app_id = cmd_buff[1]; 219 u32 app_id = cmd_buff[1];
181 u32 buffer_size = cmd_buff[2]; 220 u32 buffer_size = cmd_buff[2];
221 VAddr buffer = cmd_buff[0x104 >> 2];
182 222
183 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 223 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
184 cmd_buff[2] = 0; 224 cmd_buff[2] = next_parameter.sender_id;
185 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type 225 cmd_buff[3] = next_parameter.signal; // Signal type
186 cmd_buff[4] = 0x10; // Parameter buffer size (16) 226 cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
187 cmd_buff[5] = 0; 227 cmd_buff[5] = 0x10;
188 cmd_buff[6] = 0; 228 cmd_buff[6] = 0;
189 cmd_buff[7] = 0; 229 if (next_parameter.object != nullptr)
230 cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
231 cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
232 cmd_buff[8] = buffer;
190 233
191 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 234 if (next_parameter.data)
235 memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
236
237 LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
192} 238}
193 239
194void CancelParameter(Service::Interface* self) { 240void CancelParameter(Service::Interface* self) {
@@ -281,6 +327,28 @@ void GetAppCpuTimeLimit(Service::Interface* self) {
281 LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); 327 LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
282} 328}
283 329
330void PrepareToStartLibraryApplet(Service::Interface* self) {
331 u32* cmd_buff = Kernel::GetCommandBuffer();
332 cmd_buff[1] = HLE::Applets::Applet::Create(static_cast<AppletId>(cmd_buff[1])).raw;
333}
334
335void StartLibraryApplet(Service::Interface* self) {
336 u32* cmd_buff = Kernel::GetCommandBuffer();
337 std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(static_cast<AppletId>(cmd_buff[1]));
338
339 if (applet == nullptr) {
340 cmd_buff[1] = -1; // TODO(Subv): Find the right error code
341 return;
342 }
343
344 AppletStartupParameter parameter;
345 parameter.buffer_size = cmd_buff[2];
346 parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
347 parameter.data = Memory::GetPointer(cmd_buff[6]);
348
349 cmd_buff[1] = applet->Start(parameter).raw;
350}
351
284void Init() { 352void Init() {
285 AddService(new APT_A_Interface); 353 AddService(new APT_A_Interface);
286 AddService(new APT_S_Interface); 354 AddService(new APT_S_Interface);
@@ -318,7 +386,10 @@ void Init() {
318 386
319 // TODO(bunnei): Check if these are created in Initialize or on APT process startup. 387 // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
320 notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); 388 notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
321 start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); 389 parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
390
391 next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted);
392 next_parameter.destination_id = 0x300;
322} 393}
323 394
324void Shutdown() { 395void Shutdown() {
@@ -326,7 +397,7 @@ void Shutdown() {
326 shared_font_mem = nullptr; 397 shared_font_mem = nullptr;
327 lock = nullptr; 398 lock = nullptr;
328 notification_event = nullptr; 399 notification_event = nullptr;
329 start_event = nullptr; 400 parameter_event = nullptr;
330} 401}
331 402
332} // namespace APT 403} // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a03e1712a..510193cc8 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -11,6 +11,23 @@
11namespace Service { 11namespace Service {
12namespace APT { 12namespace APT {
13 13
14/// Holds information about the parameters used in Send/Glance/ReceiveParameter
15struct MessageParameter {
16 u32 sender_id = 0;
17 u32 destination_id = 0;
18 u32 signal = 0;
19 u32 buffer_size = 0;
20 Kernel::SharedPtr<Kernel::Object> object = nullptr;
21 u8* data = nullptr;
22};
23
24/// Holds information about the parameters used in StartLibraryApplet
25struct AppletStartupParameter {
26 u32 buffer_size = 0;
27 Kernel::SharedPtr<Kernel::Object> object = nullptr;
28 u8* data = nullptr;
29};
30
14/// Signals used by APT functions 31/// Signals used by APT functions
15enum class SignalType : u32 { 32enum class SignalType : u32 {
16 None = 0x0, 33 None = 0x0,
@@ -23,7 +40,7 @@ enum class SignalType : u32 {
23}; 40};
24 41
25/// App Id's used by APT functions 42/// App Id's used by APT functions
26enum class AppID : u32 { 43enum class AppletId : u32 {
27 HomeMenu = 0x101, 44 HomeMenu = 0x101,
28 AlternateMenu = 0x103, 45 AlternateMenu = 0x103,
29 Camera = 0x110, 46 Camera = 0x110,
@@ -45,6 +62,9 @@ enum class AppID : u32 {
45 SoftwareKeyboard2 = 0x401, 62 SoftwareKeyboard2 = 0x401,
46}; 63};
47 64
65/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
66void SendParameter(MessageParameter const& parameter);
67
48/** 68/**
49 * APT::Initialize service function 69 * APT::Initialize service function
50 * Service function that initializes the APT process for the running application 70 * Service function that initializes the APT process for the running application
@@ -249,6 +269,33 @@ void SetAppCpuTimeLimit(Service::Interface* self);
249 */ 269 */
250void GetAppCpuTimeLimit(Service::Interface* self); 270void GetAppCpuTimeLimit(Service::Interface* self);
251 271
272/**
273 * APT::PrepareToStartLibraryApplet service function
274 * Inputs:
275 * 0 : Command header [0x00180040]
276 * 1 : Id of the applet to start
277 * Outputs:
278 * 0 : Return header
279 * 1 : Result of function, 0 on success, otherwise error code
280 */
281void PrepareToStartLibraryApplet(Service::Interface* self);
282
283/**
284 * APT::StartLibraryApplet service function
285 * Inputs:
286 * 0 : Command header [0x001E0084]
287 * 1 : Id of the applet to start
288 * 2 : Buffer size
289 * 3 : Always 0?
290 * 4 : Handle passed to the applet
291 * 5 : (Size << 14) | 2
292 * 6 : Input buffer virtual address
293 * Outputs:
294 * 0 : Return header
295 * 1 : Result of function, 0 on success, otherwise error code
296 */
297void StartLibraryApplet(Service::Interface* self);
298
252/// Initialize the APT service 299/// Initialize the APT service
253void Init(); 300void Init();
254 301
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 864934245..88de339f9 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 {
10namespace APT { 10namespace APT {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010040, GetLockHandle, "GetLockHandle?"}, 13 {0x00010040, GetLockHandle, "GetLockHandle?"},
14 {0x00020080, Initialize, "Initialize?"}, 14 {0x00020080, Initialize, "Initialize?"},
15 {0x00030040, Enable, "Enable?"}, 15 {0x00030040, Enable, "Enable?"},
16 {0x00040040, nullptr, "Finalize?"}, 16 {0x00040040, nullptr, "Finalize?"},
17 {0x00050040, nullptr, "GetAppletManInfo?"}, 17 {0x00050040, nullptr, "GetAppletManInfo?"},
18 {0x00060040, nullptr, "GetAppletInfo?"}, 18 {0x00060040, nullptr, "GetAppletInfo?"},
19 {0x000D0080, ReceiveParameter, "ReceiveParameter?"}, 19 {0x00090040, IsRegistered, "IsRegistered"},
20 {0x000E0080, GlanceParameter, "GlanceParameter?"}, 20 {0x000C0104, SendParameter, "SendParameter"},
21 {0x003B0040, nullptr, "CancelLibraryApplet?"}, 21 {0x000D0080, ReceiveParameter, "ReceiveParameter"},
22 {0x00430040, NotifyToWait, "NotifyToWait?"}, 22 {0x000E0080, GlanceParameter, "GlanceParameter"},
23 {0x00440000, GetSharedFont, "GetSharedFont?"}, 23 {0x000F0100, CancelParameter, "CancelParameter"},
24 {0x004B00C2, AppletUtility, "AppletUtility?"}, 24 {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
25 {0x00550040, nullptr, "WriteInputToNsState?"}, 25 {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
26 {0x003B0040, nullptr, "CancelLibraryApplet?"},
27 {0x00430040, NotifyToWait, "NotifyToWait?"},
28 {0x00440000, GetSharedFont, "GetSharedFont?"},
29 {0x004B00C2, AppletUtility, "AppletUtility?"},
30 {0x00550040, nullptr, "WriteInputToNsState?"},
26}; 31};
27 32
28APT_A_Interface::APT_A_Interface() { 33APT_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 d006b5930..b724cd72b 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[] = {
35 {0x00150140, nullptr, "PrepareToStartApplication"}, 35 {0x00150140, nullptr, "PrepareToStartApplication"},
36 {0x00160040, nullptr, "PreloadLibraryApplet"}, 36 {0x00160040, nullptr, "PreloadLibraryApplet"},
37 {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, 37 {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
38 {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, 38 {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
39 {0x00190040, nullptr, "PrepareToStartSystemApplet"}, 39 {0x00190040, nullptr, "PrepareToStartSystemApplet"},
40 {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, 40 {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
41 {0x001B00C4, nullptr, "StartApplication"}, 41 {0x001B00C4, nullptr, "StartApplication"},
42 {0x001C0000, nullptr, "WakeupApplication"}, 42 {0x001C0000, nullptr, "WakeupApplication"},
43 {0x001D0000, nullptr, "CancelApplication"}, 43 {0x001D0000, nullptr, "CancelApplication"},
44 {0x001E0084, nullptr, "StartLibraryApplet"}, 44 {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
45 {0x001F0084, nullptr, "StartSystemApplet"}, 45 {0x001F0084, nullptr, "StartSystemApplet"},
46 {0x00200044, nullptr, "StartNewestHomeMenu"}, 46 {0x00200044, nullptr, "StartNewestHomeMenu"},
47 {0x00210000, nullptr, "OrderToCloseApplication"}, 47 {0x00210000, nullptr, "OrderToCloseApplication"},