diff options
| author | 2017-07-22 12:33:03 -0500 | |
|---|---|---|
| committer | 2017-08-07 14:53:58 -0500 | |
| commit | 73fba0de46aef0b18ef0ef5221cc23a60be4cb6c (patch) | |
| tree | a8e456efffcda56c3b1812d6ee31a85026101633 /src | |
| parent | Merge pull request #2860 from anodium/patch-1 (diff) | |
| download | yuzu-73fba0de46aef0b18ef0ef5221cc23a60be4cb6c.tar.gz yuzu-73fba0de46aef0b18ef0ef5221cc23a60be4cb6c.tar.xz yuzu-73fba0de46aef0b18ef0ef5221cc23a60be4cb6c.zip | |
Services/APT: Use an array to hold data about the 4 possible concurrent applet types (Application, Library, HomeMenu, System).
This gives each applet type its own set of events as per the real NS module.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/apt/apt.cpp | 233 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.h | 6 |
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; | |||
| 34 | static bool shared_font_relocated = false; | 34 | static bool shared_font_relocated = false; |
| 35 | 35 | ||
| 36 | static Kernel::SharedPtr<Kernel::Mutex> lock; | 36 | static Kernel::SharedPtr<Kernel::Mutex> lock; |
| 37 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event | ||
| 38 | static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event | ||
| 39 | 37 | ||
| 40 | static u32 cpu_percent; ///< CPU time available to the running application | 38 | static u32 cpu_percent; ///< CPU time available to the running application |
| 41 | 39 | ||
| @@ -44,32 +42,164 @@ static u8 unknown_ns_state_field; | |||
| 44 | 42 | ||
| 45 | static ScreencapPostPermission screen_capture_post_permission; | 43 | static 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. | ||
| 48 | static boost::optional<MessageParameter> next_parameter; | 47 | static boost::optional<MessageParameter> next_parameter; |
| 49 | 48 | ||
| 49 | enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; | ||
| 50 | |||
| 51 | static constexpr size_t NumAppletSlot = 4; | ||
| 52 | |||
| 53 | enum class AppletSlot : u8 { | ||
| 54 | Application, | ||
| 55 | SystemApplet, | ||
| 56 | HomeMenu, | ||
| 57 | LibraryApplet, | ||
| 58 | |||
| 59 | // An invalid tag | ||
| 60 | Error, | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct 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. | ||
| 73 | static std::array<AppletSlotData, NumAppletSlot> applet_slots = {}; | ||
| 74 | |||
| 75 | union 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 | ||
| 84 | static 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. | ||
| 89 | static 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 | |||
| 149 | static 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 | |||
| 50 | void SendParameter(const MessageParameter& parameter) { | 167 | void 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 | ||
| 56 | void Initialize(Service::Interface* self) { | 176 | void 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 | ||
| 75 | void GetSharedFont(Service::Interface* self) { | 205 | void 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) { | |||
| 133 | void Enable(Service::Interface* self) { | 268 | void 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 | ||
| 142 | void GetAppletManInfo(Service::Interface* self) { | 289 | void GetAppletManInfo(Service::Interface* self) { |
| @@ -154,22 +301,27 @@ void GetAppletManInfo(Service::Interface* self) { | |||
| 154 | 301 | ||
| 155 | void IsRegistered(Service::Interface* self) { | 302 | void 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 | ||
| 175 | void InquireNotification(Service::Interface* self) { | 327 | void 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 | ||
| 877 | void Shutdown() { | 1038 | void 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 |
| 74 | enum class AppletId : u32 { | 74 | enum 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 { | |||
| 119 | namespace ErrCodes { | 122 | namespace ErrCodes { |
| 120 | enum { | 123 | enum { |
| 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 |
| 126 | void SendParameter(const MessageParameter& parameter); | 130 | void SendParameter(const MessageParameter& parameter); |