summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/hle/applets/applet.cpp94
-rw-r--r--src/core/hle/applets/applet.h77
-rw-r--r--src/core/hle/applets/swkbd.cpp105
-rw-r--r--src/core/hle/applets/swkbd.h87
-rw-r--r--src/core/hle/service/apt/apt.cpp160
-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
-rw-r--r--src/core/hle/service/gsp_gpu.cpp4
-rw-r--r--src/core/hle/service/gsp_gpu.h10
11 files changed, 567 insertions, 58 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..4dcce729a
--- /dev/null
+++ b/src/core/hle/applets/applet.cpp
@@ -0,0 +1,94 @@
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/core_timing.h"
9#include "core/hle/applets/applet.h"
10#include "core/hle/applets/swkbd.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13
14// Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
15// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
16namespace std {
17 template <>
18 struct hash<Service::APT::AppletId> {
19 typedef Service::APT::AppletId argument_type;
20 typedef std::size_t result_type;
21
22 result_type operator()(const argument_type& id_code) const {
23 typedef std::underlying_type<argument_type>::type Type;
24 return std::hash<Type>()(static_cast<Type>(id_code));
25 }
26 };
27}
28
29namespace HLE {
30namespace Applets {
31
32static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
33static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
34/// The interval at which the Applet update callback will be called, 16.6ms
35static const u64 applet_update_interval_us = 16666;
36
37ResultCode Applet::Create(Service::APT::AppletId id) {
38 switch (id) {
39 case Service::APT::AppletId::SoftwareKeyboard1:
40 case Service::APT::AppletId::SoftwareKeyboard2:
41 applets[id] = std::make_shared<SoftwareKeyboard>(id);
42 break;
43 default:
44 // TODO(Subv): Find the right error code
45 return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
46 }
47
48 return RESULT_SUCCESS;
49}
50
51std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
52 auto itr = applets.find(id);
53 if (itr != applets.end())
54 return itr->second;
55 return nullptr;
56}
57
58/// Handles updating the current Applet every time it's called.
59static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
60 Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id);
61 std::shared_ptr<Applet> applet = Applet::Get(id);
62 ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id);
63
64 applet->Update();
65
66 // If the applet is still running after the last update, reschedule the event
67 if (applet->IsRunning()) {
68 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
69 applet_update_event, applet_id);
70 } else {
71 // Otherwise the applet has terminated, in which case we should clean it up
72 applets[id] = nullptr;
73 }
74}
75
76ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) {
77 ResultCode result = StartImpl(parameter);
78 if (result.IsError())
79 return result;
80 // Schedule the update event
81 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
82 return result;
83}
84
85void Init() {
86 // Register the applet update callback
87 applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent);
88}
89
90void Shutdown() {
91}
92
93}
94} // namespace
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
new file mode 100644
index 000000000..fe537e70d
--- /dev/null
+++ b/src/core/hle/applets/applet.h
@@ -0,0 +1,77 @@
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(const Service::APT::MessageParameter& 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 ResultCode Start(const Service::APT::AppletStartupParameter& parameter);
48
49 /**
50 * Whether the applet is currently executing instead of the host application or not.
51 */
52 virtual bool IsRunning() const = 0;
53
54 /**
55 * Handles an update tick for the Applet, lets it update the screen, send commands, etc.
56 */
57 virtual void Update() = 0;
58
59protected:
60 /**
61 * Handles the Applet start event, triggered from the application.
62 * @param parameter Parameter data to handle.
63 * @returns ResultCode Whether the operation was successful or not.
64 */
65 virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
66
67 Service::APT::AppletId id; ///< Id of this Applet
68};
69
70/// Initializes the HLE applets
71void Init();
72
73/// Shuts down the HLE applets
74void Shutdown();
75
76}
77} // namespace
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
new file mode 100644
index 000000000..7431ebcf8
--- /dev/null
+++ b/src/core/hle/applets/swkbd.cpp
@@ -0,0 +1,105 @@
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#include "common/string_util.h"
8
9#include "core/hle/applets/swkbd.h"
10#include "core/hle/service/hid/hid.h"
11#include "core/hle/service/gsp_gpu.h"
12#include "video_core/video_core.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15
16namespace HLE {
17namespace Applets {
18
19SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {
20 // Create the SharedMemory that will hold the framebuffer data
21 // TODO(Subv): What size should we use here?
22 using Kernel::MemoryPermission;
23 framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
24}
25
26ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
27 if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) {
28 LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
29 UNIMPLEMENTED();
30 // TODO(Subv): Find the right error code
31 return ResultCode(-1);
32 }
33
34 Service::APT::MessageParameter result;
35 // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
36 result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
37 result.data = nullptr;
38 result.buffer_size = 0;
39 result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
40 result.sender_id = static_cast<u32>(id);
41 result.object = framebuffer_memory;
42
43 Service::APT::SendParameter(result);
44 return RESULT_SUCCESS;
45}
46
47ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
48 ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
49
50 memcpy(&config, parameter.data, parameter.buffer_size);
51 text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
52
53 // TODO(Subv): Verify if this is the correct behavior
54 memset(text_memory->GetPointer(), 0, text_memory->size);
55
56 DrawScreenKeyboard();
57
58 started = true;
59 return RESULT_SUCCESS;
60}
61
62void SoftwareKeyboard::Update() {
63 // TODO(Subv): Handle input using the touch events from the HID module
64
65 // TODO(Subv): Remove this hardcoded text
66 std::u16string text = Common::UTF8ToUTF16("Citra");
67 memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t));
68
69 // TODO(Subv): Ask for input and write it to the shared memory
70 // TODO(Subv): Find out what are the possible values for the return code,
71 // some games seem to check for a hardcoded 2
72 config.return_code = 2;
73 config.text_length = 6;
74 config.text_offset = 0;
75
76 // TODO(Subv): We're finalizing the applet immediately after it's started,
77 // but we should defer this call until after all the input has been collected.
78 Finalize();
79}
80
81void SoftwareKeyboard::DrawScreenKeyboard() {
82 auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1);
83 auto info = bottom_screen->framebuffer_info[bottom_screen->index];
84
85 // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
86 memset(Memory::GetPointer(info.address_left), 0, info.stride * 320);
87
88 GSP_GPU::SetBufferSwap(1, info);
89}
90
91void SoftwareKeyboard::Finalize() {
92 // Let the application know that we're closing
93 Service::APT::MessageParameter message;
94 message.buffer_size = sizeof(SoftwareKeyboardConfig);
95 message.data = reinterpret_cast<u8*>(&config);
96 message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
97 message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
98 message.sender_id = static_cast<u32>(id);
99 Service::APT::SendParameter(message);
100
101 started = false;
102}
103
104}
105} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
new file mode 100644
index 000000000..98e81c48a
--- /dev/null
+++ b/src/core/hle/applets/swkbd.h
@@ -0,0 +1,87 @@
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
45/**
46 * The size of this structure (0x400) has been verified via reverse engineering of multiple games
47 * that use the software keyboard.
48 */
49static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong");
50
51class SoftwareKeyboard final : public Applet {
52public:
53 SoftwareKeyboard(Service::APT::AppletId id);
54 ~SoftwareKeyboard() {}
55
56 ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
57 ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
58 void Update() override;
59 bool IsRunning() const override { return started; }
60
61 /**
62 * Draws a keyboard to the current bottom screen framebuffer.
63 */
64 void DrawScreenKeyboard();
65
66 /**
67 * Sends the LibAppletClosing signal to the application,
68 * along with the relevant data buffers.
69 */
70 void Finalize();
71
72 /// TODO(Subv): Find out what this is actually used for.
73 /// It is believed that the application stores the current screen image here.
74 Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
75
76 /// SharedMemory where the output text will be stored
77 Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
78
79 /// Configuration of this instance of the SoftwareKeyboard, as received from the application
80 SoftwareKeyboardConfig config;
81
82 /// Whether this applet is currently running instead of the host application or not.
83 bool started;
84};
85
86}
87} // namespace
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index b454a2709..b364beed9 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(const MessageParameter& 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_DEBUG(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,6 @@ 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.
89 start_event->Signal();
90
91 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 98 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
92 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); 99 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
93} 100}
@@ -100,7 +107,7 @@ void GetLockHandle(Service::Interface* self) {
100 107
101 // Not sure what these parameters are used for, but retail apps check that they are 0 after 108 // Not sure what these parameters are used for, but retail apps check that they are 0 after
102 // GetLockHandle has been called. 109 // GetLockHandle has been called.
103 cmd_buff[2] = 0; 110 cmd_buff[2] = 0; // Applet Attributes, this value is passed to Enable.
104 cmd_buff[3] = 0; 111 cmd_buff[3] = 0;
105 cmd_buff[4] = 0; 112 cmd_buff[4] = 0;
106 113
@@ -110,9 +117,10 @@ void GetLockHandle(Service::Interface* self) {
110 117
111void Enable(Service::Interface* self) { 118void Enable(Service::Interface* self) {
112 u32* cmd_buff = Kernel::GetCommandBuffer(); 119 u32* cmd_buff = Kernel::GetCommandBuffer();
113 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? 120 u32 attributes = cmd_buff[1];
114 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 121 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
115 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 122 parameter_event->Signal(); // Let the application know that it has been started
123 LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
116} 124}
117 125
118void GetAppletManInfo(Service::Interface* self) { 126void GetAppletManInfo(Service::Interface* self) {
@@ -121,8 +129,8 @@ void GetAppletManInfo(Service::Interface* self) {
121 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 129 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
122 cmd_buff[2] = 0; 130 cmd_buff[2] = 0;
123 cmd_buff[3] = 0; 131 cmd_buff[3] = 0;
124 cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID 132 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 133 cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
126 134
127 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 135 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
128} 136}
@@ -131,7 +139,13 @@ void IsRegistered(Service::Interface* self) {
131 u32* cmd_buff = Kernel::GetCommandBuffer(); 139 u32* cmd_buff = Kernel::GetCommandBuffer();
132 u32 app_id = cmd_buff[1]; 140 u32 app_id = cmd_buff[1];
133 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 141 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
134 cmd_buff[2] = 1; // Set to registered 142 /// TODO(Subv): It is currently unknown what this value (0x400) means,
143 /// but i believe it is used as a global "LibraryApplet" id, to verify if there's
144 /// any LibApplet currently running. This is not verified.
145 if (app_id != 0x400)
146 cmd_buff[2] = 1; // Set to registered
147 else
148 cmd_buff[2] = 0; // Set to not registered
135 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); 149 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
136} 150}
137 151
@@ -145,50 +159,82 @@ void InquireNotification(Service::Interface* self) {
145 159
146void SendParameter(Service::Interface* self) { 160void SendParameter(Service::Interface* self) {
147 u32* cmd_buff = Kernel::GetCommandBuffer(); 161 u32* cmd_buff = Kernel::GetCommandBuffer();
148 u32 src_app_id = cmd_buff[1]; 162 u32 src_app_id = cmd_buff[1];
149 u32 dst_app_id = cmd_buff[2]; 163 u32 dst_app_id = cmd_buff[2];
150 u32 signal_type = cmd_buff[3]; 164 u32 signal_type = cmd_buff[3];
151 u32 buffer_size = cmd_buff[4]; 165 u32 buffer_size = cmd_buff[4];
152 u32 value = cmd_buff[5]; 166 u32 value = cmd_buff[5];
153 u32 handle = cmd_buff[6]; 167 u32 handle = cmd_buff[6];
154 u32 size = cmd_buff[7]; 168 u32 size = cmd_buff[7];
155 u32 in_param_buffer_ptr = cmd_buff[8]; 169 u32 buffer = cmd_buff[8];
170
171 std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
172
173 if (dest_applet == nullptr) {
174 LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
175 cmd_buff[1] = -1; // TODO(Subv): Find the right error code
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;
233
234 if (next_parameter.data)
235 memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
190 236
191 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 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) {
@@ -240,7 +286,7 @@ void AppletUtility(Service::Interface* self) {
240 u32* cmd_buff = Kernel::GetCommandBuffer(); 286 u32* cmd_buff = Kernel::GetCommandBuffer();
241 287
242 // These are from 3dbrew - I'm not really sure what they're used for. 288 // These are from 3dbrew - I'm not really sure what they're used for.
243 u32 unk = cmd_buff[1]; 289 u32 command = cmd_buff[1];
244 u32 buffer1_size = cmd_buff[2]; 290 u32 buffer1_size = cmd_buff[2];
245 u32 buffer2_size = cmd_buff[3]; 291 u32 buffer2_size = cmd_buff[3];
246 u32 buffer1_addr = cmd_buff[5]; 292 u32 buffer1_addr = cmd_buff[5];
@@ -248,8 +294,8 @@ void AppletUtility(Service::Interface* self) {
248 294
249 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 295 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
250 296
251 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " 297 LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
252 "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size, 298 "buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size,
253 buffer1_addr, buffer2_addr); 299 buffer1_addr, buffer2_addr);
254} 300}
255 301
@@ -281,11 +327,41 @@ 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 AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
333 cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
334 LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
335}
336
337void StartLibraryApplet(Service::Interface* self) {
338 u32* cmd_buff = Kernel::GetCommandBuffer();
339 AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
340 std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
341
342 LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
343
344 if (applet == nullptr) {
345 LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id);
346 cmd_buff[1] = -1; // TODO(Subv): Find the right error code
347 return;
348 }
349
350 AppletStartupParameter parameter;
351 parameter.buffer_size = cmd_buff[2];
352 parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
353 parameter.data = Memory::GetPointer(cmd_buff[6]);
354
355 cmd_buff[1] = applet->Start(parameter).raw;
356}
357
284void Init() { 358void Init() {
285 AddService(new APT_A_Interface); 359 AddService(new APT_A_Interface);
286 AddService(new APT_S_Interface); 360 AddService(new APT_S_Interface);
287 AddService(new APT_U_Interface); 361 AddService(new APT_U_Interface);
288 362
363 HLE::Applets::Init();
364
289 // Load the shared system font (if available). 365 // Load the shared system font (if available).
290 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header 366 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
291 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided 367 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
@@ -318,7 +394,10 @@ void Init() {
318 394
319 // TODO(bunnei): Check if these are created in Initialize or on APT process startup. 395 // 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"); 396 notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
321 start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); 397 parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
398
399 next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted);
400 next_parameter.destination_id = 0x300;
322} 401}
323 402
324void Shutdown() { 403void Shutdown() {
@@ -326,7 +405,8 @@ void Shutdown() {
326 shared_font_mem = nullptr; 405 shared_font_mem = nullptr;
327 lock = nullptr; 406 lock = nullptr;
328 notification_event = nullptr; 407 notification_event = nullptr;
329 start_event = nullptr; 408 parameter_event = nullptr;
409 HLE::Applets::Shutdown();
330} 410}
331 411
332} // namespace APT 412} // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a03e1712a..9f0802508 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(const MessageParameter& 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"},
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index f56bbe50f..f175085e8 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -42,7 +42,7 @@ static inline u8* GetCommandBuffer(u32 thread_id) {
42 return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); 42 return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
43} 43}
44 44
45static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 45FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
46 DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index"); 46 DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index");
47 47
48 // For each thread there are two FrameBufferUpdate fields 48 // For each thread there are two FrameBufferUpdate fields
@@ -205,7 +205,7 @@ static void ReadHWRegs(Service::Interface* self) {
205 } 205 }
206} 206}
207 207
208static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { 208void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
209 u32 base_address = 0x400000; 209 u32 base_address = 0x400000;
210 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 210 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
211 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 211 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index d9e9a1a60..268089fdd 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -173,4 +173,14 @@ public:
173 */ 173 */
174void SignalInterrupt(InterruptId interrupt_id); 174void SignalInterrupt(InterruptId interrupt_id);
175 175
176void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
177
178/**
179 * Retrieves the framebuffer info stored in the GSP shared memory for the
180 * specified screen index and thread id.
181 * @param thread_id GSP thread id of the process that accesses the structure that we are requesting.
182 * @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1).
183 * @returns FramebufferUpdate Information about the specified framebuffer.
184 */
185FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
176} // namespace 186} // namespace