summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/apt/apt.cpp233
-rw-r--r--src/core/hle/service/apt/apt.h6
2 files changed, 204 insertions, 35 deletions
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 0109fa2b2..9cfa9efde 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -34,8 +34,6 @@ static bool shared_font_loaded = false;
34static bool shared_font_relocated = false; 34static bool shared_font_relocated = false;
35 35
36static Kernel::SharedPtr<Kernel::Mutex> lock; 36static Kernel::SharedPtr<Kernel::Mutex> lock;
37static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
38static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
39 37
40static u32 cpu_percent; ///< CPU time available to the running application 38static u32 cpu_percent; ///< CPU time available to the running application
41 39
@@ -44,32 +42,164 @@ static u8 unknown_ns_state_field;
44 42
45static ScreencapPostPermission screen_capture_post_permission; 43static ScreencapPostPermission screen_capture_post_permission;
46 44
47/// Parameter data to be returned in the next call to Glance/ReceiveParameter 45/// Parameter data to be returned in the next call to Glance/ReceiveParameter.
46/// TODO(Subv): Use std::optional once we migrate to C++17.
48static boost::optional<MessageParameter> next_parameter; 47static boost::optional<MessageParameter> next_parameter;
49 48
49enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 };
50
51static constexpr size_t NumAppletSlot = 4;
52
53enum class AppletSlot : u8 {
54 Application,
55 SystemApplet,
56 HomeMenu,
57 LibraryApplet,
58
59 // An invalid tag
60 Error,
61};
62
63struct AppletSlotData {
64 AppletId applet_id;
65 AppletSlot slot;
66 bool registered;
67 u32 attributes;
68 Kernel::SharedPtr<Kernel::Event> notification_event;
69 Kernel::SharedPtr<Kernel::Event> parameter_event;
70};
71
72// Holds data about the concurrently running applets in the system.
73static std::array<AppletSlotData, NumAppletSlot> applet_slots = {};
74
75union AppletAttributes {
76 u32 raw;
77
78 BitField<0, 3, u32> applet_pos;
79
80 AppletAttributes(u32 attributes) : raw(attributes) {}
81};
82
83// Helper function to extract the AppletPos from the lower bits of the applet attributes
84static u32 GetAppletPos(AppletAttributes attributes) {
85 return attributes.applet_pos;
86}
87
88// This overload returns nullptr if no applet with the specified id has been started.
89static AppletSlotData* GetAppletSlotData(AppletId id) {
90 auto GetSlot = [](AppletSlot slot) -> AppletSlotData* {
91 return &applet_slots[static_cast<size_t>(slot)];
92 };
93
94 if (id == AppletId::Application) {
95 auto* slot = GetSlot(AppletSlot::Application);
96 if (slot->applet_id != AppletId::None)
97 return slot;
98
99 return nullptr;
100 }
101
102 if (id == AppletId::AnySystemApplet) {
103 auto* system_slot = GetSlot(AppletSlot::SystemApplet);
104 if (system_slot->applet_id != AppletId::None)
105 return system_slot;
106
107 // The Home Menu is also a system applet, but it lives in its own slot to be able to run
108 // concurrently with other system applets.
109 auto* home_slot = GetSlot(AppletSlot::HomeMenu);
110 if (home_slot->applet_id != AppletId::None)
111 return home_slot;
112
113 return nullptr;
114 }
115
116 if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) {
117 auto* slot = GetSlot(AppletSlot::LibraryApplet);
118 if (slot->applet_id == AppletId::None)
119 return nullptr;
120
121 u32 applet_pos = GetAppletPos(slot->attributes);
122
123 if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast<u32>(AppletPos::Library))
124 return slot;
125
126 if (id == AppletId::AnySysLibraryApplet &&
127 applet_pos == static_cast<u32>(AppletPos::SysLibrary))
128 return slot;
129
130 return nullptr;
131 }
132
133 if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) {
134 auto* slot = GetSlot(AppletSlot::HomeMenu);
135 if (slot->applet_id != AppletId::None)
136 return slot;
137
138 return nullptr;
139 }
140
141 for (auto& slot : applet_slots) {
142 if (slot.applet_id == id)
143 return &slot;
144 }
145
146 return nullptr;
147}
148
149static AppletSlotData* GetAppletSlotData(u32 attributes) {
150 // Mapping from AppletPos to AppletSlot
151 static constexpr std::array<AppletSlot, 6> applet_position_slots = {
152 AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet,
153 AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet};
154
155 u32 applet_pos = GetAppletPos(attributes);
156 if (applet_pos >= applet_position_slots.size())
157 return nullptr;
158
159 AppletSlot slot = applet_position_slots[applet_pos];
160
161 if (slot == AppletSlot::Error)
162 return nullptr;
163
164 return &applet_slots[static_cast<size_t>(slot)];
165}
166
50void SendParameter(const MessageParameter& parameter) { 167void SendParameter(const MessageParameter& parameter) {
51 next_parameter = parameter; 168 next_parameter = parameter;
52 // Signal the event to let the application know that a new parameter is ready to be read 169 // Signal the event to let the receiver know that a new parameter is ready to be read
53 parameter_event->Signal(); 170 auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id));
171 ASSERT(slot_data);
172
173 slot_data->parameter_event->Signal();
54} 174}
55 175
56void Initialize(Service::Interface* self) { 176void Initialize(Service::Interface* self) {
57 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080 177 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080
58 u32 app_id = rp.Pop<u32>(); 178 u32 app_id = rp.Pop<u32>();
59 u32 flags = rp.Pop<u32>(); 179 u32 attributes = rp.Pop<u32>();
60 IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); 180
61 rb.Push(RESULT_SUCCESS); 181 LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", app_id, attributes);
62 rb.PushCopyHandles(Kernel::g_handle_table.Create(notification_event).Unwrap(), 182
63 Kernel::g_handle_table.Create(parameter_event).Unwrap()); 183 auto* const slot_data = GetAppletSlotData(attributes);
184
185 // Note: The real NS service does not check if the attributes value is valid before accessing
186 // the data in the array
187 ASSERT_MSG(slot_data, "Invalid application attributes");
64 188
65 // TODO(bunnei): Check if these events are cleared every time Initialize is called. 189 if (slot_data->registered) {
66 notification_event->Clear(); 190 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
67 parameter_event->Clear(); 191 rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
192 ErrorSummary::InvalidState, ErrorLevel::Status));
193 return;
194 }
68 195
69 ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); 196 slot_data->applet_id = static_cast<AppletId>(app_id);
70 lock->Release(); 197 slot_data->attributes = attributes;
71 198
72 LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); 199 IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
200 rb.Push(RESULT_SUCCESS);
201 rb.PushCopyHandles(Kernel::g_handle_table.Create(slot_data->notification_event).Unwrap(),
202 Kernel::g_handle_table.Create(slot_data->parameter_event).Unwrap());
73} 203}
74 204
75void GetSharedFont(Service::Interface* self) { 205void GetSharedFont(Service::Interface* self) {
@@ -120,7 +250,12 @@ void GetLockHandle(Service::Interface* self) {
120 // this will cause the app to wait until parameter_event is signaled. 250 // this will cause the app to wait until parameter_event is signaled.
121 u32 applet_attributes = rp.Pop<u32>(); 251 u32 applet_attributes = rp.Pop<u32>();
122 IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); 252 IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
123 rb.Push(RESULT_SUCCESS); // No error 253 rb.Push(RESULT_SUCCESS); // No error
254
255 // TODO(Subv): The output attributes should have an AppletPos of either Library or System |
256 // Library (depending on the type of the last launched applet) if the input attributes'
257 // AppletPos has the Library bit set.
258
124 rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. 259 rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable.
125 rb.Push<u32>(0); // Least significant bit = power button state 260 rb.Push<u32>(0); // Least significant bit = power button state
126 Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).Unwrap(); 261 Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).Unwrap();
@@ -133,10 +268,22 @@ void GetLockHandle(Service::Interface* self) {
133void Enable(Service::Interface* self) { 268void Enable(Service::Interface* self) {
134 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040 269 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040
135 u32 attributes = rp.Pop<u32>(); 270 u32 attributes = rp.Pop<u32>();
271
272 LOG_DEBUG(Service_APT, "called attributes=0x%08X", attributes);
273
136 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); 274 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
137 rb.Push(RESULT_SUCCESS); // No error 275
138 parameter_event->Signal(); // Let the application know that it has been started 276 auto* const slot_data = GetAppletSlotData(attributes);
139 LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); 277
278 if (!slot_data) {
279 rb.Push(ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet,
280 ErrorSummary::InvalidState, ErrorLevel::Status));
281 return;
282 }
283
284 slot_data->registered = true;
285
286 rb.Push(RESULT_SUCCESS);
140} 287}
141 288
142void GetAppletManInfo(Service::Interface* self) { 289void GetAppletManInfo(Service::Interface* self) {
@@ -154,22 +301,27 @@ void GetAppletManInfo(Service::Interface* self) {
154 301
155void IsRegistered(Service::Interface* self) { 302void IsRegistered(Service::Interface* self) {
156 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040 303 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040
157 u32 app_id = rp.Pop<u32>(); 304 AppletId app_id = static_cast<AppletId>(rp.Pop<u32>());
158 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); 305 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
159 rb.Push(RESULT_SUCCESS); // No error 306 rb.Push(RESULT_SUCCESS); // No error
160 307
161 // TODO(Subv): An application is considered "registered" if it has already called APT::Enable 308 auto* const slot_data = GetAppletSlotData(app_id);
162 // handle this properly once we implement multiprocess support. 309
163 bool is_registered = false; // Set to not registered by default 310 // Check if an LLE applet was registered first, then fallback to HLE applets
311 bool is_registered = slot_data && slot_data->registered;
164 312
165 if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { 313 if (!is_registered) {
166 is_registered = HLE::Applets::IsLibraryAppletRunning(); 314 if (app_id == AppletId::AnyLibraryApplet) {
167 } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { 315 is_registered = HLE::Applets::IsLibraryAppletRunning();
168 is_registered = true; // Set to registered 316 } else if (auto applet = HLE::Applets::Applet::Get(app_id)) {
317 // The applet exists, set it as registered.
318 is_registered = true;
319 }
169 } 320 }
321
170 rb.Push(is_registered); 322 rb.Push(is_registered);
171 323
172 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); 324 LOG_DEBUG(Service_APT, "called app_id=0x%08X", static_cast<u32>(app_id));
173} 325}
174 326
175void InquireNotification(Service::Interface* self) { 327void InquireNotification(Service::Interface* self) {
@@ -864,14 +1016,23 @@ void Init() {
864 screen_capture_post_permission = 1016 screen_capture_post_permission =
865 ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value 1017 ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
866 1018
867 // TODO(bunnei): Check if these are created in Initialize or on APT process startup. 1019 for (size_t slot = 0; slot < applet_slots.size(); ++slot) {
868 notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification"); 1020 auto& slot_data = applet_slots[slot];
869 parameter_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Start"); 1021 slot_data.slot = static_cast<AppletSlot>(slot);
1022 slot_data.applet_id = AppletId::None;
1023 slot_data.attributes = 0;
1024 slot_data.registered = false;
1025 slot_data.notification_event =
1026 Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification");
1027 slot_data.parameter_event =
1028 Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter");
1029 }
870 1030
871 // Initialize the parameter to wake up the application. 1031 // Initialize the parameter to wake up the application.
872 next_parameter.emplace(); 1032 next_parameter.emplace();
873 next_parameter->signal = static_cast<u32>(SignalType::Wakeup); 1033 next_parameter->signal = static_cast<u32>(SignalType::Wakeup);
874 next_parameter->destination_id = static_cast<u32>(AppletId::Application); 1034 next_parameter->destination_id = static_cast<u32>(AppletId::Application);
1035 applet_slots[static_cast<size_t>(AppletSlot::Application)].parameter_event->Signal();
875} 1036}
876 1037
877void Shutdown() { 1038void Shutdown() {
@@ -879,8 +1040,12 @@ void Shutdown() {
879 shared_font_loaded = false; 1040 shared_font_loaded = false;
880 shared_font_relocated = false; 1041 shared_font_relocated = false;
881 lock = nullptr; 1042 lock = nullptr;
882 notification_event = nullptr; 1043
883 parameter_event = nullptr; 1044 for (auto& slot : applet_slots) {
1045 slot.registered = false;
1046 slot.notification_event = nullptr;
1047 slot.parameter_event = nullptr;
1048 }
884 1049
885 next_parameter = boost::none; 1050 next_parameter = boost::none;
886 1051
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 106754853..96b28b438 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -72,6 +72,8 @@ enum class SignalType : u32 {
72 72
73/// App Id's used by APT functions 73/// App Id's used by APT functions
74enum class AppletId : u32 { 74enum class AppletId : u32 {
75 None = 0,
76 AnySystemApplet = 0x100,
75 HomeMenu = 0x101, 77 HomeMenu = 0x101,
76 AlternateMenu = 0x103, 78 AlternateMenu = 0x103,
77 Camera = 0x110, 79 Camera = 0x110,
@@ -83,6 +85,7 @@ enum class AppletId : u32 {
83 Miiverse = 0x117, 85 Miiverse = 0x117,
84 MiiversePost = 0x118, 86 MiiversePost = 0x118,
85 AmiiboSettings = 0x119, 87 AmiiboSettings = 0x119,
88 AnySysLibraryApplet = 0x200,
86 SoftwareKeyboard1 = 0x201, 89 SoftwareKeyboard1 = 0x201,
87 Ed1 = 0x202, 90 Ed1 = 0x202,
88 PnoteApp = 0x204, 91 PnoteApp = 0x204,
@@ -119,8 +122,9 @@ enum class ScreencapPostPermission : u32 {
119namespace ErrCodes { 122namespace ErrCodes {
120enum { 123enum {
121 ParameterPresent = 2, 124 ParameterPresent = 2,
125 InvalidAppletSlot = 4,
122}; 126};
123} 127} // namespace ErrCodes
124 128
125/// Send a parameter to the currently-running application, which will read it via ReceiveParameter 129/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
126void SendParameter(const MessageParameter& parameter); 130void SendParameter(const MessageParameter& parameter);