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