mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #3408 from wwylele/apt-new-framework
APT/Applet: move applet management into its own class
This commit is contained in:
		
						commit
						40b9e55e60
					
				
					 17 changed files with 773 additions and 623 deletions
				
			
		|  | @ -164,6 +164,8 @@ add_library(core STATIC | ||||||
|     hle/service/am/am_sys.h |     hle/service/am/am_sys.h | ||||||
|     hle/service/am/am_u.cpp |     hle/service/am/am_u.cpp | ||||||
|     hle/service/am/am_u.h |     hle/service/am/am_u.h | ||||||
|  |     hle/service/apt/applet_manager.cpp | ||||||
|  |     hle/service/apt/applet_manager.h | ||||||
|     hle/service/apt/apt.cpp |     hle/service/apt/apt.cpp | ||||||
|     hle/service/apt/apt.h |     hle/service/apt/apt.h | ||||||
|     hle/service/apt/apt_a.cpp |     hle/service/apt/apt_a.cpp | ||||||
|  | @ -174,6 +176,7 @@ add_library(core STATIC | ||||||
|     hle/service/apt/apt_u.h |     hle/service/apt/apt_u.h | ||||||
|     hle/service/apt/bcfnt/bcfnt.cpp |     hle/service/apt/bcfnt/bcfnt.cpp | ||||||
|     hle/service/apt/bcfnt/bcfnt.h |     hle/service/apt/bcfnt/bcfnt.h | ||||||
|  |     hle/service/apt/errors.h | ||||||
|     hle/service/boss/boss.cpp |     hle/service/boss/boss.cpp | ||||||
|     hle/service/boss/boss.h |     hle/service/boss/boss.h | ||||||
|     hle/service/boss/boss_p.cpp |     hle/service/boss/boss_p.cpp | ||||||
|  |  | ||||||
|  | @ -15,7 +15,6 @@ | ||||||
| #include "core/hle/applets/mint.h" | #include "core/hle/applets/mint.h" | ||||||
| #include "core/hle/applets/swkbd.h" | #include "core/hle/applets/swkbd.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/apt/apt.h" |  | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
|  | @ -43,23 +42,24 @@ static CoreTiming::EventType* applet_update_event = nullptr; | ||||||
| /// The interval at which the Applet update callback will be called, 16.6ms
 | /// The interval at which the Applet update callback will be called, 16.6ms
 | ||||||
| static const u64 applet_update_interval_us = 16666; | static const u64 applet_update_interval_us = 16666; | ||||||
| 
 | 
 | ||||||
| ResultCode Applet::Create(Service::APT::AppletId id) { | ResultCode Applet::Create(Service::APT::AppletId id, | ||||||
|  |                           std::weak_ptr<Service::APT::AppletManager> manager) { | ||||||
|     switch (id) { |     switch (id) { | ||||||
|     case Service::APT::AppletId::SoftwareKeyboard1: |     case Service::APT::AppletId::SoftwareKeyboard1: | ||||||
|     case Service::APT::AppletId::SoftwareKeyboard2: |     case Service::APT::AppletId::SoftwareKeyboard2: | ||||||
|         applets[id] = std::make_shared<SoftwareKeyboard>(id); |         applets[id] = std::make_shared<SoftwareKeyboard>(id, std::move(manager)); | ||||||
|         break; |         break; | ||||||
|     case Service::APT::AppletId::Ed1: |     case Service::APT::AppletId::Ed1: | ||||||
|     case Service::APT::AppletId::Ed2: |     case Service::APT::AppletId::Ed2: | ||||||
|         applets[id] = std::make_shared<MiiSelector>(id); |         applets[id] = std::make_shared<MiiSelector>(id, std::move(manager)); | ||||||
|         break; |         break; | ||||||
|     case Service::APT::AppletId::Error: |     case Service::APT::AppletId::Error: | ||||||
|     case Service::APT::AppletId::Error2: |     case Service::APT::AppletId::Error2: | ||||||
|         applets[id] = std::make_shared<ErrEula>(id); |         applets[id] = std::make_shared<ErrEula>(id, std::move(manager)); | ||||||
|         break; |         break; | ||||||
|     case Service::APT::AppletId::Mint: |     case Service::APT::AppletId::Mint: | ||||||
|     case Service::APT::AppletId::Mint2: |     case Service::APT::AppletId::Mint2: | ||||||
|         applets[id] = std::make_shared<Mint>(id); |         applets[id] = std::make_shared<Mint>(id, std::move(manager)); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         LOG_ERROR(Service_APT, "Could not create applet %u", static_cast<u32>(id)); |         LOG_ERROR(Service_APT, "Could not create applet %u", static_cast<u32>(id)); | ||||||
|  | @ -110,6 +110,14 @@ bool Applet::IsRunning() const { | ||||||
|     return is_running; |     return is_running; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Applet::SendParameter(const Service::APT::MessageParameter& parameter) { | ||||||
|  |     if (auto locked = manager.lock()) { | ||||||
|  |         locked->CancelAndSendParameter(parameter); | ||||||
|  |     } else { | ||||||
|  |         LOG_ERROR(Service_APT, "called after destructing applet manager"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool IsLibraryAppletRunning() { | bool IsLibraryAppletRunning() { | ||||||
|     // Check the applets map for instances of any applet
 |     // Check the applets map for instances of any applet
 | ||||||
|     for (auto itr = applets.begin(); itr != applets.end(); ++itr) |     for (auto itr = applets.begin(); itr != applets.end(); ++itr) | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/apt/apt.h" | #include "core/hle/service/apt/applet_manager.h" | ||||||
| 
 | 
 | ||||||
| namespace HLE { | namespace HLE { | ||||||
| namespace Applets { | namespace Applets { | ||||||
|  | @ -21,7 +21,8 @@ public: | ||||||
|      * @param id Id of the applet to create. |      * @param id Id of the applet to create. | ||||||
|      * @returns ResultCode Whether the operation was successful or not. |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|      */ |      */ | ||||||
|     static ResultCode Create(Service::APT::AppletId id); |     static ResultCode Create(Service::APT::AppletId id, | ||||||
|  |                              std::weak_ptr<Service::APT::AppletManager> manager); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Retrieves the Applet instance identified by the specified id. |      * Retrieves the Applet instance identified by the specified id. | ||||||
|  | @ -55,7 +56,8 @@ public: | ||||||
|     virtual void Update() = 0; |     virtual void Update() = 0; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     explicit Applet(Service::APT::AppletId id) : id(id) {} |     Applet(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) | ||||||
|  |         : id(id), manager(std::move(manager)) {} | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Handles the Applet start event, triggered from the application. |      * Handles the Applet start event, triggered from the application. | ||||||
|  | @ -69,6 +71,11 @@ protected: | ||||||
| 
 | 
 | ||||||
|     /// Whether this applet is currently running instead of the host application or not.
 |     /// Whether this applet is currently running instead of the host application or not.
 | ||||||
|     bool is_running = false; |     bool is_running = false; | ||||||
|  | 
 | ||||||
|  |     void SendParameter(const Service::APT::MessageParameter& parameter); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::weak_ptr<Service::APT::AppletManager> manager; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Returns whether a library applet is currently running
 | /// Returns whether a library applet is currently running
 | ||||||
|  |  | ||||||
|  | @ -10,8 +10,8 @@ namespace HLE { | ||||||
| namespace Applets { | namespace Applets { | ||||||
| 
 | 
 | ||||||
| ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ||||||
|     if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { |     if (parameter.signal != Service::APT::SignalType::Request) { | ||||||
|         LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |         LOG_ERROR(Service_APT, "unsupported signal %u", static_cast<u32>(parameter.signal)); | ||||||
|         UNIMPLEMENTED(); |         UNIMPLEMENTED(); | ||||||
|         // TODO(Subv): Find the right error code
 |         // TODO(Subv): Find the right error code
 | ||||||
|         return ResultCode(-1); |         return ResultCode(-1); | ||||||
|  | @ -36,13 +36,13 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param | ||||||
| 
 | 
 | ||||||
|     // Send the response message with the newly created SharedMemory
 |     // Send the response message with the newly created SharedMemory
 | ||||||
|     Service::APT::MessageParameter result; |     Service::APT::MessageParameter result; | ||||||
|     result.signal = static_cast<u32>(Service::APT::SignalType::Response); |     result.signal = Service::APT::SignalType::Response; | ||||||
|     result.buffer.clear(); |     result.buffer.clear(); | ||||||
|     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     result.destination_id = Service::APT::AppletId::Application; | ||||||
|     result.sender_id = static_cast<u32>(id); |     result.sender_id = id; | ||||||
|     result.object = framebuffer_memory; |     result.object = framebuffer_memory; | ||||||
| 
 | 
 | ||||||
|     Service::APT::SendParameter(result); |     SendParameter(result); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -57,10 +57,10 @@ ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parame | ||||||
|     Service::APT::MessageParameter message; |     Service::APT::MessageParameter message; | ||||||
|     message.buffer.resize(parameter.buffer.size()); |     message.buffer.resize(parameter.buffer.size()); | ||||||
|     std::fill(message.buffer.begin(), message.buffer.end(), 0); |     std::fill(message.buffer.begin(), message.buffer.end(), 0); | ||||||
|     message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); |     message.signal = Service::APT::SignalType::WakeupByExit; | ||||||
|     message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     message.destination_id = Service::APT::AppletId::Application; | ||||||
|     message.sender_id = static_cast<u32>(id); |     message.sender_id = id; | ||||||
|     Service::APT::SendParameter(message); |     SendParameter(message); | ||||||
| 
 | 
 | ||||||
|     is_running = false; |     is_running = false; | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
|  |  | ||||||
|  | @ -12,7 +12,8 @@ namespace Applets { | ||||||
| 
 | 
 | ||||||
| class ErrEula final : public Applet { | class ErrEula final : public Applet { | ||||||
| public: | public: | ||||||
|     explicit ErrEula(Service::APT::AppletId id) : Applet(id) {} |     explicit ErrEula(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) | ||||||
|  |         : Applet(id, std::move(manager)) {} | ||||||
| 
 | 
 | ||||||
|     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; |     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||||||
|     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; |     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||||||
|  |  | ||||||
|  | @ -18,8 +18,8 @@ namespace HLE { | ||||||
| namespace Applets { | namespace Applets { | ||||||
| 
 | 
 | ||||||
| ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ||||||
|     if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { |     if (parameter.signal != Service::APT::SignalType::Request) { | ||||||
|         LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |         LOG_ERROR(Service_APT, "unsupported signal %u", static_cast<u32>(parameter.signal)); | ||||||
|         UNIMPLEMENTED(); |         UNIMPLEMENTED(); | ||||||
|         // TODO(Subv): Find the right error code
 |         // TODO(Subv): Find the right error code
 | ||||||
|         return ResultCode(-1); |         return ResultCode(-1); | ||||||
|  | @ -43,13 +43,13 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p | ||||||
| 
 | 
 | ||||||
|     // Send the response message with the newly created SharedMemory
 |     // Send the response message with the newly created SharedMemory
 | ||||||
|     Service::APT::MessageParameter result; |     Service::APT::MessageParameter result; | ||||||
|     result.signal = static_cast<u32>(Service::APT::SignalType::Response); |     result.signal = Service::APT::SignalType::Response; | ||||||
|     result.buffer.clear(); |     result.buffer.clear(); | ||||||
|     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     result.destination_id = Service::APT::AppletId::Application; | ||||||
|     result.sender_id = static_cast<u32>(id); |     result.sender_id = id; | ||||||
|     result.object = framebuffer_memory; |     result.object = framebuffer_memory; | ||||||
| 
 | 
 | ||||||
|     Service::APT::SendParameter(result); |     SendParameter(result); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -72,10 +72,10 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa | ||||||
|     Service::APT::MessageParameter message; |     Service::APT::MessageParameter message; | ||||||
|     message.buffer.resize(sizeof(MiiResult)); |     message.buffer.resize(sizeof(MiiResult)); | ||||||
|     std::memcpy(message.buffer.data(), &result, message.buffer.size()); |     std::memcpy(message.buffer.data(), &result, message.buffer.size()); | ||||||
|     message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); |     message.signal = Service::APT::SignalType::WakeupByExit; | ||||||
|     message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     message.destination_id = Service::APT::AppletId::Application; | ||||||
|     message.sender_id = static_cast<u32>(id); |     message.sender_id = id; | ||||||
|     Service::APT::SendParameter(message); |     SendParameter(message); | ||||||
| 
 | 
 | ||||||
|     is_running = false; |     is_running = false; | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
|  |  | ||||||
|  | @ -60,7 +60,8 @@ ASSERT_REG_POSITION(guest_mii_name, 0x6C); | ||||||
| 
 | 
 | ||||||
| class MiiSelector final : public Applet { | class MiiSelector final : public Applet { | ||||||
| public: | public: | ||||||
|     MiiSelector(Service::APT::AppletId id) : Applet(id) {} |     MiiSelector(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) | ||||||
|  |         : Applet(id, std::move(manager)) {} | ||||||
| 
 | 
 | ||||||
|     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; |     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||||||
|     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; |     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||||||
|  |  | ||||||
|  | @ -10,8 +10,8 @@ namespace HLE { | ||||||
| namespace Applets { | namespace Applets { | ||||||
| 
 | 
 | ||||||
| ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ||||||
|     if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { |     if (parameter.signal != Service::APT::SignalType::Request) { | ||||||
|         LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |         LOG_ERROR(Service_APT, "unsupported signal %u", static_cast<u32>(parameter.signal)); | ||||||
|         UNIMPLEMENTED(); |         UNIMPLEMENTED(); | ||||||
|         // TODO(Subv): Find the right error code
 |         // TODO(Subv): Find the right error code
 | ||||||
|         return ResultCode(-1); |         return ResultCode(-1); | ||||||
|  | @ -36,13 +36,13 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete | ||||||
| 
 | 
 | ||||||
|     // Send the response message with the newly created SharedMemory
 |     // Send the response message with the newly created SharedMemory
 | ||||||
|     Service::APT::MessageParameter result; |     Service::APT::MessageParameter result; | ||||||
|     result.signal = static_cast<u32>(Service::APT::SignalType::Response); |     result.signal = Service::APT::SignalType::Response; | ||||||
|     result.buffer.clear(); |     result.buffer.clear(); | ||||||
|     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     result.destination_id = Service::APT::AppletId::Application; | ||||||
|     result.sender_id = static_cast<u32>(id); |     result.sender_id = id; | ||||||
|     result.object = framebuffer_memory; |     result.object = framebuffer_memory; | ||||||
| 
 | 
 | ||||||
|     Service::APT::SendParameter(result); |     SendParameter(result); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -57,10 +57,10 @@ ResultCode Mint::StartImpl(const Service::APT::AppletStartupParameter& parameter | ||||||
|     Service::APT::MessageParameter message; |     Service::APT::MessageParameter message; | ||||||
|     message.buffer.resize(parameter.buffer.size()); |     message.buffer.resize(parameter.buffer.size()); | ||||||
|     std::fill(message.buffer.begin(), message.buffer.end(), 0); |     std::fill(message.buffer.begin(), message.buffer.end(), 0); | ||||||
|     message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); |     message.signal = Service::APT::SignalType::WakeupByExit; | ||||||
|     message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     message.destination_id = Service::APT::AppletId::Application; | ||||||
|     message.sender_id = static_cast<u32>(id); |     message.sender_id = id; | ||||||
|     Service::APT::SendParameter(message); |     SendParameter(message); | ||||||
| 
 | 
 | ||||||
|     is_running = false; |     is_running = false; | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
|  |  | ||||||
|  | @ -12,7 +12,8 @@ namespace Applets { | ||||||
| 
 | 
 | ||||||
| class Mint final : public Applet { | class Mint final : public Applet { | ||||||
| public: | public: | ||||||
|     explicit Mint(Service::APT::AppletId id) : Applet(id) {} |     explicit Mint(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) | ||||||
|  |         : Applet(id, std::move(manager)) {} | ||||||
| 
 | 
 | ||||||
|     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; |     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||||||
|     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; |     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||||||
|  |  | ||||||
|  | @ -21,8 +21,8 @@ namespace HLE { | ||||||
| namespace Applets { | namespace Applets { | ||||||
| 
 | 
 | ||||||
| ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { | ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { | ||||||
|     if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { |     if (parameter.signal != Service::APT::SignalType::Request) { | ||||||
|         LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |         LOG_ERROR(Service_APT, "unsupported signal %u", static_cast<u32>(parameter.signal)); | ||||||
|         UNIMPLEMENTED(); |         UNIMPLEMENTED(); | ||||||
|         // TODO(Subv): Find the right error code
 |         // TODO(Subv): Find the right error code
 | ||||||
|         return ResultCode(-1); |         return ResultCode(-1); | ||||||
|  | @ -46,13 +46,13 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con | ||||||
| 
 | 
 | ||||||
|     // Send the response message with the newly created SharedMemory
 |     // Send the response message with the newly created SharedMemory
 | ||||||
|     Service::APT::MessageParameter result; |     Service::APT::MessageParameter result; | ||||||
|     result.signal = static_cast<u32>(Service::APT::SignalType::Response); |     result.signal = Service::APT::SignalType::Response; | ||||||
|     result.buffer.clear(); |     result.buffer.clear(); | ||||||
|     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     result.destination_id = Service::APT::AppletId::Application; | ||||||
|     result.sender_id = static_cast<u32>(id); |     result.sender_id = id; | ||||||
|     result.object = framebuffer_memory; |     result.object = framebuffer_memory; | ||||||
| 
 | 
 | ||||||
|     Service::APT::SendParameter(result); |     SendParameter(result); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -107,10 +107,10 @@ void SoftwareKeyboard::Finalize() { | ||||||
|     Service::APT::MessageParameter message; |     Service::APT::MessageParameter message; | ||||||
|     message.buffer.resize(sizeof(SoftwareKeyboardConfig)); |     message.buffer.resize(sizeof(SoftwareKeyboardConfig)); | ||||||
|     std::memcpy(message.buffer.data(), &config, message.buffer.size()); |     std::memcpy(message.buffer.data(), &config, message.buffer.size()); | ||||||
|     message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); |     message.signal = Service::APT::SignalType::WakeupByExit; | ||||||
|     message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |     message.destination_id = Service::APT::AppletId::Application; | ||||||
|     message.sender_id = static_cast<u32>(id); |     message.sender_id = id; | ||||||
|     Service::APT::SendParameter(message); |     SendParameter(message); | ||||||
| 
 | 
 | ||||||
|     is_running = false; |     is_running = false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -52,7 +52,8 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config | ||||||
| 
 | 
 | ||||||
| class SoftwareKeyboard final : public Applet { | class SoftwareKeyboard final : public Applet { | ||||||
| public: | public: | ||||||
|     SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {} |     SoftwareKeyboard(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) | ||||||
|  |         : Applet(id, std::move(manager)) {} | ||||||
| 
 | 
 | ||||||
|     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; |     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||||||
|     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; |     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||||||
|  |  | ||||||
							
								
								
									
										440
									
								
								src/core/hle/service/apt/applet_manager.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										440
									
								
								src/core/hle/service/apt/applet_manager.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,440 @@ | ||||||
|  | // Copyright 2018 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "common/common_paths.h" | ||||||
|  | #include "core/hle/applets/applet.h" | ||||||
|  | #include "core/hle/service/apt/applet_manager.h" | ||||||
|  | #include "core/hle/service/apt/errors.h" | ||||||
|  | #include "core/hle/service/cfg/cfg.h" | ||||||
|  | #include "core/hle/service/ns/ns.h" | ||||||
|  | 
 | ||||||
|  | namespace Service { | ||||||
|  | namespace APT { | ||||||
|  | 
 | ||||||
|  | enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; | ||||||
|  | 
 | ||||||
|  | struct AppletTitleData { | ||||||
|  |     // There are two possible applet ids for each applet.
 | ||||||
|  |     std::array<AppletId, 2> applet_ids; | ||||||
|  | 
 | ||||||
|  |     // There's a specific TitleId per region for each applet.
 | ||||||
|  |     static constexpr size_t NumRegions = 7; | ||||||
|  |     std::array<u64, NumRegions> title_ids; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static constexpr size_t NumApplets = 29; | ||||||
|  | static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{ | ||||||
|  |     {AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, | ||||||
|  |      0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, | ||||||
|  |     {AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102, | ||||||
|  |      0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}, | ||||||
|  |     {AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902, | ||||||
|  |      0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}, | ||||||
|  |     {AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02, | ||||||
|  |      0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}, | ||||||
|  |     {AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02, | ||||||
|  |      0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}, | ||||||
|  |     {AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02, | ||||||
|  |      0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602}, | ||||||
|  |     {AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02, | ||||||
|  |      0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}, | ||||||
|  |     {AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002, | ||||||
|  |      0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802}, | ||||||
|  |     {AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02, | ||||||
|  |      0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902}, | ||||||
|  |     // These values obtained from an older NS dump firmware 4.5
 | ||||||
|  |     {AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, | ||||||
|  |      0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}, | ||||||
|  |     // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
 | ||||||
|  |     //  0x4003000008302, 0x0, 0x0, 0x0},
 | ||||||
|  |     {AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902, | ||||||
|  |      0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}, | ||||||
|  |     {AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, | ||||||
|  |      0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, | ||||||
|  |     {AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, | ||||||
|  |      0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, | ||||||
|  |     {AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302, | ||||||
|  |      0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}, | ||||||
|  |     {AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402, | ||||||
|  |      0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}, | ||||||
|  |     {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, | ||||||
|  |      0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, | ||||||
|  |     {AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602, | ||||||
|  |      0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902}, | ||||||
|  |     {AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, | ||||||
|  |      0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502}, | ||||||
|  |     {AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602, | ||||||
|  |      0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602}, | ||||||
|  |     // TODO(Subv): Fill in the rest of the titleids
 | ||||||
|  | }}; | ||||||
|  | 
 | ||||||
|  | static u64 GetTitleIdForApplet(AppletId id) { | ||||||
|  |     ASSERT_MSG(id != AppletId::None, "Invalid applet id"); | ||||||
|  | 
 | ||||||
|  |     auto itr = std::find_if(applet_titleids.begin(), applet_titleids.end(), | ||||||
|  |                             [id](const AppletTitleData& data) { | ||||||
|  |                                 return data.applet_ids[0] == id || data.applet_ids[1] == id; | ||||||
|  |                             }); | ||||||
|  | 
 | ||||||
|  |     ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x%03X", static_cast<u32>(id)); | ||||||
|  | 
 | ||||||
|  |     return itr->title_ids[CFG::GetRegionValue()]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletId id) { | ||||||
|  |     auto GetSlot = [this](AppletSlot slot) -> AppletSlotData* { | ||||||
|  |         return &applet_slots[static_cast<size_t>(slot)]; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     if (id == AppletId::Application) { | ||||||
|  |         auto* slot = GetSlot(AppletSlot::Application); | ||||||
|  |         if (slot->applet_id != AppletId::None) | ||||||
|  |             return slot; | ||||||
|  | 
 | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (id == AppletId::AnySystemApplet) { | ||||||
|  |         auto* system_slot = GetSlot(AppletSlot::SystemApplet); | ||||||
|  |         if (system_slot->applet_id != AppletId::None) | ||||||
|  |             return system_slot; | ||||||
|  | 
 | ||||||
|  |         // The Home Menu is also a system applet, but it lives in its own slot to be able to run
 | ||||||
|  |         // concurrently with other system applets.
 | ||||||
|  |         auto* home_slot = GetSlot(AppletSlot::HomeMenu); | ||||||
|  |         if (home_slot->applet_id != AppletId::None) | ||||||
|  |             return home_slot; | ||||||
|  | 
 | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { | ||||||
|  |         auto* slot = GetSlot(AppletSlot::LibraryApplet); | ||||||
|  |         if (slot->applet_id == AppletId::None) | ||||||
|  |             return nullptr; | ||||||
|  | 
 | ||||||
|  |         u32 applet_pos = slot->attributes.applet_pos; | ||||||
|  | 
 | ||||||
|  |         if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast<u32>(AppletPos::Library)) | ||||||
|  |             return slot; | ||||||
|  | 
 | ||||||
|  |         if (id == AppletId::AnySysLibraryApplet && | ||||||
|  |             applet_pos == static_cast<u32>(AppletPos::SysLibrary)) | ||||||
|  |             return slot; | ||||||
|  | 
 | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { | ||||||
|  |         auto* slot = GetSlot(AppletSlot::HomeMenu); | ||||||
|  |         if (slot->applet_id != AppletId::None) | ||||||
|  |             return slot; | ||||||
|  | 
 | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (auto& slot : applet_slots) { | ||||||
|  |         if (slot.applet_id == id) | ||||||
|  |             return &slot; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletAttributes attributes) { | ||||||
|  |     // Mapping from AppletPos to AppletSlot
 | ||||||
|  |     static constexpr std::array<AppletSlot, 6> applet_position_slots = { | ||||||
|  |         AppletSlot::Application,   AppletSlot::LibraryApplet, AppletSlot::SystemApplet, | ||||||
|  |         AppletSlot::LibraryApplet, AppletSlot::Error,         AppletSlot::LibraryApplet}; | ||||||
|  | 
 | ||||||
|  |     u32 applet_pos = attributes.applet_pos; | ||||||
|  |     if (applet_pos >= applet_position_slots.size()) | ||||||
|  |         return nullptr; | ||||||
|  | 
 | ||||||
|  |     AppletSlot slot = applet_position_slots[applet_pos]; | ||||||
|  | 
 | ||||||
|  |     if (slot == AppletSlot::Error) | ||||||
|  |         return nullptr; | ||||||
|  | 
 | ||||||
|  |     // The Home Menu is a system applet, however, it has its own applet slot so that it can run
 | ||||||
|  |     // concurrently with other system applets.
 | ||||||
|  |     if (slot == AppletSlot::SystemApplet && attributes.is_home_menu) | ||||||
|  |         return &applet_slots[static_cast<size_t>(AppletSlot::HomeMenu)]; | ||||||
|  | 
 | ||||||
|  |     return &applet_slots[static_cast<size_t>(slot)]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AppletManager::CancelAndSendParameter(const MessageParameter& parameter) { | ||||||
|  |     next_parameter = parameter; | ||||||
|  |     // Signal the event to let the receiver know that a new parameter is ready to be read
 | ||||||
|  |     auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id)); | ||||||
|  |     if (slot_data == nullptr) { | ||||||
|  |         LOG_DEBUG(Service_APT, "No applet was registered with the id %03X", | ||||||
|  |                   static_cast<u32>(parameter.destination_id)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     slot_data->parameter_event->Signal(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode AppletManager::SendParameter(const MessageParameter& parameter) { | ||||||
|  |     // A new parameter can not be sent if the previous one hasn't been consumed yet
 | ||||||
|  |     if (next_parameter) { | ||||||
|  |         return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, | ||||||
|  |                           ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  |     CancelAndSendParameter(parameter); | ||||||
|  |     if (auto dest_applet = HLE::Applets::Applet::Get(parameter.destination_id)) { | ||||||
|  |         return dest_applet->ReceiveParameter(parameter); | ||||||
|  |     } else { | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<MessageParameter> AppletManager::GlanceParameter(AppletId app_id) { | ||||||
|  |     if (!next_parameter) { | ||||||
|  |         return ResultCode(ErrorDescription::NoData, ErrorModule::Applet, ErrorSummary::InvalidState, | ||||||
|  |                           ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (next_parameter->destination_id != app_id) { | ||||||
|  |         return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||||||
|  |                           ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     MessageParameter parameter = *next_parameter; | ||||||
|  | 
 | ||||||
|  |     // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter.
 | ||||||
|  |     if (next_parameter->signal == SignalType::DspSleep || | ||||||
|  |         next_parameter->signal == SignalType::DspWakeup) | ||||||
|  |         next_parameter = boost::none; | ||||||
|  | 
 | ||||||
|  |     return MakeResult<MessageParameter>(parameter); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<MessageParameter> AppletManager::ReceiveParameter(AppletId app_id) { | ||||||
|  |     auto result = GlanceParameter(app_id); | ||||||
|  |     if (result.Succeeded()) { | ||||||
|  |         // Clear the parameter
 | ||||||
|  |         next_parameter = boost::none; | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool AppletManager::CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver, | ||||||
|  |                                     AppletId receiver_appid) { | ||||||
|  |     bool cancellation_success = true; | ||||||
|  | 
 | ||||||
|  |     if (!next_parameter) { | ||||||
|  |         cancellation_success = false; | ||||||
|  |     } else { | ||||||
|  |         if (check_sender && next_parameter->sender_id != sender_appid) | ||||||
|  |             cancellation_success = false; | ||||||
|  | 
 | ||||||
|  |         if (check_receiver && next_parameter->destination_id != receiver_appid) | ||||||
|  |             cancellation_success = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (cancellation_success) | ||||||
|  |         next_parameter = boost::none; | ||||||
|  | 
 | ||||||
|  |     return cancellation_success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId app_id, | ||||||
|  |                                                                      AppletAttributes attributes) { | ||||||
|  |     auto* const slot_data = GetAppletSlotData(attributes); | ||||||
|  | 
 | ||||||
|  |     // Note: The real NS service does not check if the attributes value is valid before accessing
 | ||||||
|  |     // the data in the array
 | ||||||
|  |     ASSERT_MSG(slot_data, "Invalid application attributes"); | ||||||
|  | 
 | ||||||
|  |     if (slot_data->registered) { | ||||||
|  |         return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, | ||||||
|  |                           ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     slot_data->applet_id = static_cast<AppletId>(app_id); | ||||||
|  |     slot_data->attributes.raw = attributes.raw; | ||||||
|  | 
 | ||||||
|  |     if (slot_data->applet_id == AppletId::Application || | ||||||
|  |         slot_data->applet_id == AppletId::HomeMenu) { | ||||||
|  |         // Initialize the APT parameter to wake up the application.
 | ||||||
|  |         next_parameter.emplace(); | ||||||
|  |         next_parameter->signal = SignalType::Wakeup; | ||||||
|  |         next_parameter->sender_id = AppletId::None; | ||||||
|  |         next_parameter->destination_id = app_id; | ||||||
|  |         // Not signaling the parameter event will cause the application (or Home Menu) to hang
 | ||||||
|  |         // during startup. In the real console, it is usually the Kernel and Home Menu who cause NS
 | ||||||
|  |         // to signal the HomeMenu and Application parameter events, respectively.
 | ||||||
|  |         slot_data->parameter_event->Signal(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return MakeResult<InitializeResult>( | ||||||
|  |         {slot_data->notification_event, slot_data->parameter_event}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode AppletManager::Enable(AppletAttributes attributes) { | ||||||
|  |     auto* const slot_data = GetAppletSlotData(attributes); | ||||||
|  | 
 | ||||||
|  |     if (!slot_data) { | ||||||
|  |         return ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, | ||||||
|  |                           ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     slot_data->registered = true; | ||||||
|  | 
 | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool AppletManager::IsRegistered(AppletId app_id) { | ||||||
|  |     const auto* slot_data = GetAppletSlotData(app_id); | ||||||
|  | 
 | ||||||
|  |     // Check if an LLE applet was registered first, then fallback to HLE applets
 | ||||||
|  |     bool is_registered = slot_data && slot_data->registered; | ||||||
|  | 
 | ||||||
|  |     if (!is_registered) { | ||||||
|  |         if (app_id == AppletId::AnyLibraryApplet) { | ||||||
|  |             is_registered = HLE::Applets::IsLibraryAppletRunning(); | ||||||
|  |         } else if (auto applet = HLE::Applets::Applet::Get(app_id)) { | ||||||
|  |             // The applet exists, set it as registered.
 | ||||||
|  |             is_registered = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return is_registered; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { | ||||||
|  |     // The real APT service returns an error if there's a pending APT parameter when this function
 | ||||||
|  |     // is called.
 | ||||||
|  |     if (next_parameter) { | ||||||
|  |         return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, | ||||||
|  |                           ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)]; | ||||||
|  | 
 | ||||||
|  |     if (slot.registered) { | ||||||
|  |         return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, | ||||||
|  |                           ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); | ||||||
|  |     if (process) { | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // If we weren't able to load the native applet title, try to fallback to an HLE implementation.
 | ||||||
|  |     auto applet = HLE::Applets::Applet::Get(applet_id); | ||||||
|  |     if (applet) { | ||||||
|  |         LOG_WARNING(Service_APT, "applet has already been started id=%08X", | ||||||
|  |                     static_cast<u32>(applet_id)); | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } else { | ||||||
|  |         return HLE::Applets::Applet::Create(applet_id, shared_from_this()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode AppletManager::PreloadLibraryApplet(AppletId applet_id) { | ||||||
|  |     const auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)]; | ||||||
|  | 
 | ||||||
|  |     if (slot.registered) { | ||||||
|  |         return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, | ||||||
|  |                           ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); | ||||||
|  |     if (process) { | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // If we weren't able to load the native applet title, try to fallback to an HLE implementation.
 | ||||||
|  |     auto applet = HLE::Applets::Applet::Get(applet_id); | ||||||
|  |     if (applet) { | ||||||
|  |         LOG_WARNING(Service_APT, "applet has already been started id=%08X", | ||||||
|  |                     static_cast<u32>(applet_id)); | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } else { | ||||||
|  |         return HLE::Applets::Applet::Create(applet_id, shared_from_this()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode AppletManager::FinishPreloadingLibraryApplet(AppletId applet_id) { | ||||||
|  |     // TODO(Subv): This function should fail depending on the applet preparation state.
 | ||||||
|  |     auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)]; | ||||||
|  |     slot.loaded = true; | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode AppletManager::StartLibraryApplet(AppletId applet_id, | ||||||
|  |                                              Kernel::SharedPtr<Kernel::Object> object, | ||||||
|  |                                              const std::vector<u8>& buffer) { | ||||||
|  |     MessageParameter param; | ||||||
|  |     param.destination_id = applet_id; | ||||||
|  |     param.sender_id = AppletId::Application; | ||||||
|  |     param.object = object; | ||||||
|  |     param.signal = SignalType::Wakeup; | ||||||
|  |     param.buffer = buffer; | ||||||
|  |     CancelAndSendParameter(param); | ||||||
|  | 
 | ||||||
|  |     // In case the applet is being HLEd, attempt to communicate with it.
 | ||||||
|  |     if (auto applet = HLE::Applets::Applet::Get(applet_id)) { | ||||||
|  |         AppletStartupParameter parameter; | ||||||
|  |         parameter.object = object; | ||||||
|  |         parameter.buffer = buffer; | ||||||
|  |         return applet->Start(parameter); | ||||||
|  |     } else { | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_id) { | ||||||
|  |     const auto* slot = GetAppletSlotData(app_id); | ||||||
|  | 
 | ||||||
|  |     if (slot == nullptr || !slot->registered) { | ||||||
|  |         // See if there's an HLE applet and try to use it before erroring out.
 | ||||||
|  |         auto hle_applet = HLE::Applets::Applet::Get(app_id); | ||||||
|  |         if (hle_applet == nullptr) { | ||||||
|  |             return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, | ||||||
|  |                               ErrorSummary::NotFound, ErrorLevel::Status); | ||||||
|  |         } | ||||||
|  |         LOG_WARNING(Service_APT, "Using HLE applet info for applet %03X", static_cast<u32>(app_id)); | ||||||
|  |         // TODO(Subv): Get the title id for the current applet and write it in the response[2-3]
 | ||||||
|  |         return MakeResult<AppletInfo>({0, Service::FS::MediaType::NAND, true, true, 0}); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (app_id == AppletId::Application) { | ||||||
|  |         // TODO(Subv): Implement this once Application launching is implemented
 | ||||||
|  |         LOG_ERROR(Service_APT, "Unimplemented GetAppletInfo(Application)"); | ||||||
|  |         return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||||||
|  |                           ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return MakeResult<AppletInfo>({GetTitleIdForApplet(app_id), Service::FS::MediaType::NAND, | ||||||
|  |                                    slot->registered, slot->loaded, slot->attributes.raw}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppletManager::AppletManager() { | ||||||
|  |     for (size_t slot = 0; slot < applet_slots.size(); ++slot) { | ||||||
|  |         auto& slot_data = applet_slots[slot]; | ||||||
|  |         slot_data.slot = static_cast<AppletSlot>(slot); | ||||||
|  |         slot_data.applet_id = AppletId::None; | ||||||
|  |         slot_data.attributes.raw = 0; | ||||||
|  |         slot_data.registered = false; | ||||||
|  |         slot_data.loaded = false; | ||||||
|  |         slot_data.notification_event = | ||||||
|  |             Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); | ||||||
|  |         slot_data.parameter_event = | ||||||
|  |             Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); | ||||||
|  |     } | ||||||
|  |     HLE::Applets::Init(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppletManager::~AppletManager() { | ||||||
|  |     HLE::Applets::Shutdown(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace APT
 | ||||||
|  | } // namespace Service
 | ||||||
							
								
								
									
										178
									
								
								src/core/hle/service/apt/applet_manager.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/core/hle/service/apt/applet_manager.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,178 @@ | ||||||
|  | // Copyright 2018 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <array> | ||||||
|  | #include <vector> | ||||||
|  | #include <boost/optional.hpp> | ||||||
|  | #include "core/hle/kernel/event.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | #include "core/hle/service/fs/archive.h" | ||||||
|  | 
 | ||||||
|  | namespace Service { | ||||||
|  | namespace APT { | ||||||
|  | 
 | ||||||
|  | /// Signals used by APT functions
 | ||||||
|  | enum class SignalType : u32 { | ||||||
|  |     None = 0x0, | ||||||
|  |     Wakeup = 0x1, | ||||||
|  |     Request = 0x2, | ||||||
|  |     Response = 0x3, | ||||||
|  |     Exit = 0x4, | ||||||
|  |     Message = 0x5, | ||||||
|  |     HomeButtonSingle = 0x6, | ||||||
|  |     HomeButtonDouble = 0x7, | ||||||
|  |     DspSleep = 0x8, | ||||||
|  |     DspWakeup = 0x9, | ||||||
|  |     WakeupByExit = 0xA, | ||||||
|  |     WakeupByPause = 0xB, | ||||||
|  |     WakeupByCancel = 0xC, | ||||||
|  |     WakeupByCancelAll = 0xD, | ||||||
|  |     WakeupByPowerButtonClick = 0xE, | ||||||
|  |     WakeupToJumpHome = 0xF, | ||||||
|  |     RequestForSysApplet = 0x10, | ||||||
|  |     WakeupToLaunchApplication = 0x11, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// App Id's used by APT functions
 | ||||||
|  | enum class AppletId : u32 { | ||||||
|  |     None = 0, | ||||||
|  |     AnySystemApplet = 0x100, | ||||||
|  |     HomeMenu = 0x101, | ||||||
|  |     AlternateMenu = 0x103, | ||||||
|  |     Camera = 0x110, | ||||||
|  |     FriendList = 0x112, | ||||||
|  |     GameNotes = 0x113, | ||||||
|  |     InternetBrowser = 0x114, | ||||||
|  |     InstructionManual = 0x115, | ||||||
|  |     Notifications = 0x116, | ||||||
|  |     Miiverse = 0x117, | ||||||
|  |     MiiversePost = 0x118, | ||||||
|  |     AmiiboSettings = 0x119, | ||||||
|  |     AnySysLibraryApplet = 0x200, | ||||||
|  |     SoftwareKeyboard1 = 0x201, | ||||||
|  |     Ed1 = 0x202, | ||||||
|  |     PnoteApp = 0x204, | ||||||
|  |     SnoteApp = 0x205, | ||||||
|  |     Error = 0x206, | ||||||
|  |     Mint = 0x207, | ||||||
|  |     Extrapad = 0x208, | ||||||
|  |     Memolib = 0x209, | ||||||
|  |     Application = 0x300, | ||||||
|  |     Tiger = 0x301, | ||||||
|  |     AnyLibraryApplet = 0x400, | ||||||
|  |     SoftwareKeyboard2 = 0x401, | ||||||
|  |     Ed2 = 0x402, | ||||||
|  |     PnoteApp2 = 0x404, | ||||||
|  |     SnoteApp2 = 0x405, | ||||||
|  |     Error2 = 0x406, | ||||||
|  |     Mint2 = 0x407, | ||||||
|  |     Extrapad2 = 0x408, | ||||||
|  |     Memolib2 = 0x409, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// Holds information about the parameters used in Send/Glance/ReceiveParameter
 | ||||||
|  | struct MessageParameter { | ||||||
|  |     AppletId sender_id = AppletId::None; | ||||||
|  |     AppletId destination_id = AppletId::None; | ||||||
|  |     SignalType signal = SignalType::None; | ||||||
|  |     Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||||||
|  |     std::vector<u8> buffer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// Holds information about the parameters used in StartLibraryApplet
 | ||||||
|  | struct AppletStartupParameter { | ||||||
|  |     Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||||||
|  |     std::vector<u8> buffer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | union AppletAttributes { | ||||||
|  |     u32 raw; | ||||||
|  | 
 | ||||||
|  |     BitField<0, 3, u32> applet_pos; | ||||||
|  |     BitField<29, 1, u32> is_home_menu; | ||||||
|  | 
 | ||||||
|  |     AppletAttributes() : raw(0) {} | ||||||
|  |     AppletAttributes(u32 attributes) : raw(attributes) {} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class AppletManager : public std::enable_shared_from_this<AppletManager> { | ||||||
|  | public: | ||||||
|  |     AppletManager(); | ||||||
|  |     ~AppletManager(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Clears any existing parameter and places a new one. This function is currently only used by | ||||||
|  |      * HLE Applets and should be likely removed in the future | ||||||
|  |      */ | ||||||
|  |     void CancelAndSendParameter(const MessageParameter& parameter); | ||||||
|  | 
 | ||||||
|  |     ResultCode SendParameter(const MessageParameter& parameter); | ||||||
|  |     ResultVal<MessageParameter> GlanceParameter(AppletId app_id); | ||||||
|  |     ResultVal<MessageParameter> ReceiveParameter(AppletId app_id); | ||||||
|  |     bool CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver, | ||||||
|  |                          AppletId receiver_appid); | ||||||
|  | 
 | ||||||
|  |     struct InitializeResult { | ||||||
|  |         Kernel::SharedPtr<Kernel::Event> notification_event; | ||||||
|  |         Kernel::SharedPtr<Kernel::Event> parameter_event; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes); | ||||||
|  |     ResultCode Enable(AppletAttributes attributes); | ||||||
|  |     bool IsRegistered(AppletId app_id); | ||||||
|  |     ResultCode PrepareToStartLibraryApplet(AppletId applet_id); | ||||||
|  |     ResultCode PreloadLibraryApplet(AppletId applet_id); | ||||||
|  |     ResultCode FinishPreloadingLibraryApplet(AppletId applet_id); | ||||||
|  |     ResultCode StartLibraryApplet(AppletId applet_id, Kernel::SharedPtr<Kernel::Object> object, | ||||||
|  |                                   const std::vector<u8>& buffer); | ||||||
|  | 
 | ||||||
|  |     struct AppletInfo { | ||||||
|  |         u64 title_id; | ||||||
|  |         Service::FS::MediaType media_type; | ||||||
|  |         bool registered; | ||||||
|  |         bool loaded; | ||||||
|  |         u32 attributes; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     ResultVal<AppletInfo> GetAppletInfo(AppletId app_id); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     /// Parameter data to be returned in the next call to Glance/ReceiveParameter.
 | ||||||
|  |     /// TODO(Subv): Use std::optional once we migrate to C++17.
 | ||||||
|  |     boost::optional<MessageParameter> next_parameter; | ||||||
|  | 
 | ||||||
|  |     static constexpr size_t NumAppletSlot = 4; | ||||||
|  | 
 | ||||||
|  |     enum class AppletSlot : u8 { | ||||||
|  |         Application, | ||||||
|  |         SystemApplet, | ||||||
|  |         HomeMenu, | ||||||
|  |         LibraryApplet, | ||||||
|  | 
 | ||||||
|  |         // An invalid tag
 | ||||||
|  |         Error, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct AppletSlotData { | ||||||
|  |         AppletId applet_id; | ||||||
|  |         AppletSlot slot; | ||||||
|  |         bool registered; | ||||||
|  |         bool loaded; | ||||||
|  |         AppletAttributes attributes; | ||||||
|  |         Kernel::SharedPtr<Kernel::Event> notification_event; | ||||||
|  |         Kernel::SharedPtr<Kernel::Event> parameter_event; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // Holds data about the concurrently running applets in the system.
 | ||||||
|  |     std::array<AppletSlotData, NumAppletSlot> applet_slots = {}; | ||||||
|  | 
 | ||||||
|  |     // This overload returns nullptr if no applet with the specified id has been started.
 | ||||||
|  |     AppletSlotData* GetAppletSlotData(AppletId id); | ||||||
|  |     AppletSlotData* GetAppletSlotData(AppletAttributes attributes); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace APT
 | ||||||
|  | } // namespace Service
 | ||||||
|  | @ -2,18 +2,17 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include <boost/optional.hpp> |  | ||||||
| #include "common/common_paths.h" | #include "common/common_paths.h" | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/file_sys/file_backend.h" | #include "core/file_sys/file_backend.h" | ||||||
| #include "core/hle/applets/applet.h" | #include "core/hle/applets/applet.h" | ||||||
| #include "core/hle/kernel/event.h" |  | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
| #include "core/hle/romfs.h" | #include "core/hle/romfs.h" | ||||||
|  | #include "core/hle/service/apt/applet_manager.h" | ||||||
| #include "core/hle/service/apt/apt.h" | #include "core/hle/service/apt/apt.h" | ||||||
| #include "core/hle/service/apt/apt_a.h" | #include "core/hle/service/apt/apt_a.h" | ||||||
| #include "core/hle/service/apt/apt_s.h" | #include "core/hle/service/apt/apt_s.h" | ||||||
|  | @ -21,7 +20,6 @@ | ||||||
| #include "core/hle/service/apt/bcfnt/bcfnt.h" | #include "core/hle/service/apt/bcfnt/bcfnt.h" | ||||||
| #include "core/hle/service/cfg/cfg.h" | #include "core/hle/service/cfg/cfg.h" | ||||||
| #include "core/hle/service/fs/archive.h" | #include "core/hle/service/fs/archive.h" | ||||||
| #include "core/hle/service/ns/ns.h" |  | ||||||
| #include "core/hle/service/ptm/ptm.h" | #include "core/hle/service/ptm/ptm.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| #include "core/hw/aes/ccm.h" | #include "core/hw/aes/ccm.h" | ||||||
|  | @ -44,251 +42,26 @@ static u8 unknown_ns_state_field; | ||||||
| 
 | 
 | ||||||
| static ScreencapPostPermission screen_capture_post_permission; | static ScreencapPostPermission screen_capture_post_permission; | ||||||
| 
 | 
 | ||||||
| /// Parameter data to be returned in the next call to Glance/ReceiveParameter.
 | static std::shared_ptr<AppletManager> applet_manager; | ||||||
| /// TODO(Subv): Use std::optional once we migrate to C++17.
 |  | ||||||
| static boost::optional<MessageParameter> next_parameter; |  | ||||||
| 
 |  | ||||||
| enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; |  | ||||||
| 
 |  | ||||||
| static constexpr size_t NumAppletSlot = 4; |  | ||||||
| 
 |  | ||||||
| enum class AppletSlot : u8 { |  | ||||||
|     Application, |  | ||||||
|     SystemApplet, |  | ||||||
|     HomeMenu, |  | ||||||
|     LibraryApplet, |  | ||||||
| 
 |  | ||||||
|     // An invalid tag
 |  | ||||||
|     Error, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| union AppletAttributes { |  | ||||||
|     u32 raw; |  | ||||||
| 
 |  | ||||||
|     BitField<0, 3, u32> applet_pos; |  | ||||||
|     BitField<29, 1, u32> is_home_menu; |  | ||||||
| 
 |  | ||||||
|     AppletAttributes() : raw(0) {} |  | ||||||
|     AppletAttributes(u32 attributes) : raw(attributes) {} |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct AppletSlotData { |  | ||||||
|     AppletId applet_id; |  | ||||||
|     AppletSlot slot; |  | ||||||
|     bool registered; |  | ||||||
|     bool loaded; |  | ||||||
|     AppletAttributes attributes; |  | ||||||
|     Kernel::SharedPtr<Kernel::Event> notification_event; |  | ||||||
|     Kernel::SharedPtr<Kernel::Event> parameter_event; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| // Holds data about the concurrently running applets in the system.
 |  | ||||||
| static std::array<AppletSlotData, NumAppletSlot> applet_slots = {}; |  | ||||||
| 
 |  | ||||||
| struct AppletTitleData { |  | ||||||
|     // There are two possible applet ids for each applet.
 |  | ||||||
|     std::array<AppletId, 2> applet_ids; |  | ||||||
| 
 |  | ||||||
|     // There's a specific TitleId per region for each applet.
 |  | ||||||
|     static constexpr size_t NumRegions = 7; |  | ||||||
|     std::array<u64, NumRegions> title_ids; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static constexpr size_t NumApplets = 29; |  | ||||||
| static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{ |  | ||||||
|     {AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, |  | ||||||
|      0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, |  | ||||||
|     {AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102, |  | ||||||
|      0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}, |  | ||||||
|     {AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902, |  | ||||||
|      0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}, |  | ||||||
|     {AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02, |  | ||||||
|      0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}, |  | ||||||
|     {AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02, |  | ||||||
|      0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}, |  | ||||||
|     {AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02, |  | ||||||
|      0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602}, |  | ||||||
|     {AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02, |  | ||||||
|      0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}, |  | ||||||
|     {AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002, |  | ||||||
|      0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802}, |  | ||||||
|     {AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02, |  | ||||||
|      0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902}, |  | ||||||
|     // These values obtained from an older NS dump firmware 4.5
 |  | ||||||
|     {AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, |  | ||||||
|      0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}, |  | ||||||
|     // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
 |  | ||||||
|     //  0x4003000008302, 0x0, 0x0, 0x0},
 |  | ||||||
|     {AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902, |  | ||||||
|      0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}, |  | ||||||
|     {AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, |  | ||||||
|      0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, |  | ||||||
|     {AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, |  | ||||||
|      0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, |  | ||||||
|     {AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302, |  | ||||||
|      0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}, |  | ||||||
|     {AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402, |  | ||||||
|      0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}, |  | ||||||
|     {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, |  | ||||||
|      0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, |  | ||||||
|     {AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602, |  | ||||||
|      0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902}, |  | ||||||
|     {AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, |  | ||||||
|      0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502}, |  | ||||||
|     {AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602, |  | ||||||
|      0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602}, |  | ||||||
|     // TODO(Subv): Fill in the rest of the titleids
 |  | ||||||
| }}; |  | ||||||
| 
 |  | ||||||
| static u64 GetTitleIdForApplet(AppletId id) { |  | ||||||
|     ASSERT_MSG(id != AppletId::None, "Invalid applet id"); |  | ||||||
| 
 |  | ||||||
|     auto itr = std::find_if(applet_titleids.begin(), applet_titleids.end(), |  | ||||||
|                             [id](const AppletTitleData& data) { |  | ||||||
|                                 return data.applet_ids[0] == id || data.applet_ids[1] == id; |  | ||||||
|                             }); |  | ||||||
| 
 |  | ||||||
|     ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x%03X", static_cast<u32>(id)); |  | ||||||
| 
 |  | ||||||
|     return itr->title_ids[CFG::GetRegionValue()]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // This overload returns nullptr if no applet with the specified id has been started.
 |  | ||||||
| static AppletSlotData* GetAppletSlotData(AppletId id) { |  | ||||||
|     auto GetSlot = [](AppletSlot slot) -> AppletSlotData* { |  | ||||||
|         return &applet_slots[static_cast<size_t>(slot)]; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     if (id == AppletId::Application) { |  | ||||||
|         auto* slot = GetSlot(AppletSlot::Application); |  | ||||||
|         if (slot->applet_id != AppletId::None) |  | ||||||
|             return slot; |  | ||||||
| 
 |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (id == AppletId::AnySystemApplet) { |  | ||||||
|         auto* system_slot = GetSlot(AppletSlot::SystemApplet); |  | ||||||
|         if (system_slot->applet_id != AppletId::None) |  | ||||||
|             return system_slot; |  | ||||||
| 
 |  | ||||||
|         // The Home Menu is also a system applet, but it lives in its own slot to be able to run
 |  | ||||||
|         // concurrently with other system applets.
 |  | ||||||
|         auto* home_slot = GetSlot(AppletSlot::HomeMenu); |  | ||||||
|         if (home_slot->applet_id != AppletId::None) |  | ||||||
|             return home_slot; |  | ||||||
| 
 |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { |  | ||||||
|         auto* slot = GetSlot(AppletSlot::LibraryApplet); |  | ||||||
|         if (slot->applet_id == AppletId::None) |  | ||||||
|             return nullptr; |  | ||||||
| 
 |  | ||||||
|         u32 applet_pos = slot->attributes.applet_pos; |  | ||||||
| 
 |  | ||||||
|         if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast<u32>(AppletPos::Library)) |  | ||||||
|             return slot; |  | ||||||
| 
 |  | ||||||
|         if (id == AppletId::AnySysLibraryApplet && |  | ||||||
|             applet_pos == static_cast<u32>(AppletPos::SysLibrary)) |  | ||||||
|             return slot; |  | ||||||
| 
 |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { |  | ||||||
|         auto* slot = GetSlot(AppletSlot::HomeMenu); |  | ||||||
|         if (slot->applet_id != AppletId::None) |  | ||||||
|             return slot; |  | ||||||
| 
 |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for (auto& slot : applet_slots) { |  | ||||||
|         if (slot.applet_id == id) |  | ||||||
|             return &slot; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return nullptr; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static AppletSlotData* GetAppletSlotData(AppletAttributes attributes) { |  | ||||||
|     // Mapping from AppletPos to AppletSlot
 |  | ||||||
|     static constexpr std::array<AppletSlot, 6> applet_position_slots = { |  | ||||||
|         AppletSlot::Application,   AppletSlot::LibraryApplet, AppletSlot::SystemApplet, |  | ||||||
|         AppletSlot::LibraryApplet, AppletSlot::Error,         AppletSlot::LibraryApplet}; |  | ||||||
| 
 |  | ||||||
|     u32 applet_pos = attributes.applet_pos; |  | ||||||
|     if (applet_pos >= applet_position_slots.size()) |  | ||||||
|         return nullptr; |  | ||||||
| 
 |  | ||||||
|     AppletSlot slot = applet_position_slots[applet_pos]; |  | ||||||
| 
 |  | ||||||
|     if (slot == AppletSlot::Error) |  | ||||||
|         return nullptr; |  | ||||||
| 
 |  | ||||||
|     // The Home Menu is a system applet, however, it has its own applet slot so that it can run
 |  | ||||||
|     // concurrently with other system applets.
 |  | ||||||
|     if (slot == AppletSlot::SystemApplet && attributes.is_home_menu) |  | ||||||
|         return &applet_slots[static_cast<size_t>(AppletSlot::HomeMenu)]; |  | ||||||
| 
 |  | ||||||
|     return &applet_slots[static_cast<size_t>(slot)]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void SendParameter(const MessageParameter& parameter) { |  | ||||||
|     next_parameter = parameter; |  | ||||||
|     // Signal the event to let the receiver know that a new parameter is ready to be read
 |  | ||||||
|     auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id)); |  | ||||||
|     if (slot_data == nullptr) { |  | ||||||
|         LOG_DEBUG(Service_APT, "No applet was registered with the id %03X", |  | ||||||
|                   parameter.destination_id); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     slot_data->parameter_event->Signal(); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void Initialize(Service::Interface* self) { | void Initialize(Service::Interface* self) { | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080
 |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080
 | ||||||
|     u32 app_id = rp.Pop<u32>(); |     AppletId app_id = rp.PopEnum<AppletId>(); | ||||||
|     u32 attributes = rp.Pop<u32>(); |     u32 attributes = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", app_id, attributes); |     LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", static_cast<u32>(app_id), | ||||||
|  |               attributes); | ||||||
| 
 | 
 | ||||||
|     auto* const slot_data = GetAppletSlotData(attributes); |     auto result = applet_manager->Initialize(app_id, attributes); | ||||||
| 
 |     if (result.Failed()) { | ||||||
|     // Note: The real NS service does not check if the attributes value is valid before accessing
 |  | ||||||
|     // the data in the array
 |  | ||||||
|     ASSERT_MSG(slot_data, "Invalid application attributes"); |  | ||||||
| 
 |  | ||||||
|     if (slot_data->registered) { |  | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|         rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, |         rb.Push(result.Code()); | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |     } else { | ||||||
|         return; |         auto events = std::move(result).Unwrap(); | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     slot_data->applet_id = static_cast<AppletId>(app_id); |  | ||||||
|     slot_data->attributes.raw = attributes; |  | ||||||
| 
 |  | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|     rb.PushCopyHandles(Kernel::g_handle_table.Create(slot_data->notification_event).Unwrap(), |         rb.PushCopyHandles(Kernel::g_handle_table.Create(events.notification_event).Unwrap(), | ||||||
|                        Kernel::g_handle_table.Create(slot_data->parameter_event).Unwrap()); |                            Kernel::g_handle_table.Create(events.parameter_event).Unwrap()); | ||||||
| 
 |  | ||||||
|     if (slot_data->applet_id == AppletId::Application || |  | ||||||
|         slot_data->applet_id == AppletId::HomeMenu) { |  | ||||||
|         // Initialize the APT parameter to wake up the application.
 |  | ||||||
|         next_parameter.emplace(); |  | ||||||
|         next_parameter->signal = static_cast<u32>(SignalType::Wakeup); |  | ||||||
|         next_parameter->sender_id = static_cast<u32>(AppletId::None); |  | ||||||
|         next_parameter->destination_id = app_id; |  | ||||||
|         // Not signaling the parameter event will cause the application (or Home Menu) to hang
 |  | ||||||
|         // during startup. In the real console, it is usually the Kernel and Home Menu who cause NS
 |  | ||||||
|         // to signal the HomeMenu and Application parameter events, respectively.
 |  | ||||||
|         slot_data->parameter_event->Signal(); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -508,18 +281,7 @@ void Enable(Service::Interface* self) { | ||||||
|     LOG_DEBUG(Service_APT, "called attributes=0x%08X", attributes); |     LOG_DEBUG(Service_APT, "called attributes=0x%08X", attributes); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
| 
 |     rb.Push(applet_manager->Enable(attributes)); | ||||||
|     auto* const slot_data = GetAppletSlotData(attributes); |  | ||||||
| 
 |  | ||||||
|     if (!slot_data) { |  | ||||||
|         rb.Push(ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, |  | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     slot_data->registered = true; |  | ||||||
| 
 |  | ||||||
|     rb.Push(RESULT_SUCCESS); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetAppletManInfo(Service::Interface* self) { | void GetAppletManInfo(Service::Interface* self) { | ||||||
|  | @ -540,22 +302,7 @@ void IsRegistered(Service::Interface* self) { | ||||||
|     AppletId app_id = static_cast<AppletId>(rp.Pop<u32>()); |     AppletId app_id = static_cast<AppletId>(rp.Pop<u32>()); | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|     rb.Push(RESULT_SUCCESS); // No error
 |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
| 
 |     rb.Push(applet_manager->IsRegistered(app_id)); | ||||||
|     const auto* slot_data = GetAppletSlotData(app_id); |  | ||||||
| 
 |  | ||||||
|     // Check if an LLE applet was registered first, then fallback to HLE applets
 |  | ||||||
|     bool is_registered = slot_data && slot_data->registered; |  | ||||||
| 
 |  | ||||||
|     if (!is_registered) { |  | ||||||
|         if (app_id == AppletId::AnyLibraryApplet) { |  | ||||||
|             is_registered = HLE::Applets::IsLibraryAppletRunning(); |  | ||||||
|         } else if (auto applet = HLE::Applets::Applet::Get(app_id)) { |  | ||||||
|             // The applet exists, set it as registered.
 |  | ||||||
|             is_registered = true; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     rb.Push(is_registered); |  | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called app_id=0x%08X", static_cast<u32>(app_id)); |     LOG_DEBUG(Service_APT, "called app_id=0x%08X", static_cast<u32>(app_id)); | ||||||
| } | } | ||||||
|  | @ -571,9 +318,9 @@ void InquireNotification(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
| void SendParameter(Service::Interface* self) { | void SendParameter(Service::Interface* self) { | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104
 |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104
 | ||||||
|     u32 src_app_id = rp.Pop<u32>(); |     AppletId src_app_id = rp.PopEnum<AppletId>(); | ||||||
|     u32 dst_app_id = rp.Pop<u32>(); |     AppletId dst_app_id = rp.PopEnum<AppletId>(); | ||||||
|     u32 signal_type = rp.Pop<u32>(); |     SignalType signal_type = rp.PopEnum<SignalType>(); | ||||||
|     u32 buffer_size = rp.Pop<u32>(); |     u32 buffer_size = rp.Pop<u32>(); | ||||||
|     Kernel::Handle handle = rp.PopHandle(); |     Kernel::Handle handle = rp.PopHandle(); | ||||||
|     size_t size; |     size_t size; | ||||||
|  | @ -582,17 +329,11 @@ void SendParameter(Service::Interface* self) { | ||||||
|     LOG_DEBUG(Service_APT, |     LOG_DEBUG(Service_APT, | ||||||
|               "called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," |               "called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," | ||||||
|               "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", |               "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", | ||||||
|               src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); |               static_cast<u32>(src_app_id), static_cast<u32>(dst_app_id), | ||||||
|  |               static_cast<u32>(signal_type), buffer_size, handle, size, buffer); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
| 
 | 
 | ||||||
|     // A new parameter can not be sent if the previous one hasn't been consumed yet
 |  | ||||||
|     if (next_parameter) { |  | ||||||
|         rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, |  | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     MessageParameter param; |     MessageParameter param; | ||||||
|     param.destination_id = dst_app_id; |     param.destination_id = dst_app_id; | ||||||
|     param.sender_id = src_app_id; |     param.sender_id = src_app_id; | ||||||
|  | @ -601,19 +342,12 @@ void SendParameter(Service::Interface* self) { | ||||||
|     param.buffer.resize(buffer_size); |     param.buffer.resize(buffer_size); | ||||||
|     Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); |     Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); | ||||||
| 
 | 
 | ||||||
|     SendParameter(param); |     rb.Push(applet_manager->SendParameter(param)); | ||||||
| 
 |  | ||||||
|     // If the applet is running in HLE mode, use the HLE interface to communicate with it.
 |  | ||||||
|     if (auto dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id))) { |  | ||||||
|         rb.Push(dest_applet->ReceiveParameter(param)); |  | ||||||
|     } else { |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ReceiveParameter(Service::Interface* self) { | void ReceiveParameter(Service::Interface* self) { | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080
 |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080
 | ||||||
|     u32 app_id = rp.Pop<u32>(); |     AppletId app_id = rp.PopEnum<AppletId>(); | ||||||
|     u32 buffer_size = rp.Pop<u32>(); |     u32 buffer_size = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     size_t static_buff_size; |     size_t static_buff_size; | ||||||
|  | @ -624,27 +358,22 @@ void ReceiveParameter(Service::Interface* self) { | ||||||
|             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", |             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||||||
|             buffer_size, static_buff_size); |             buffer_size, static_buff_size); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); |     LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", static_cast<u32>(app_id), | ||||||
|  |               buffer_size); | ||||||
| 
 | 
 | ||||||
|     if (!next_parameter) { |     auto next_parameter = applet_manager->ReceiveParameter(app_id); | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |  | ||||||
|         rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, |  | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (next_parameter->destination_id != app_id) { |     if (next_parameter.Failed()) { | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|         rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, |         rb.Push(next_parameter.Code()); | ||||||
|                            ErrorLevel::Status)); |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); |     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); | ||||||
| 
 | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); // No error
 |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     rb.Push(next_parameter->sender_id); |     rb.PushEnum(next_parameter->sender_id); | ||||||
|     rb.Push(next_parameter->signal); // Signal type
 |     rb.PushEnum(next_parameter->signal); // Signal type
 | ||||||
|     ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); |     ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||||||
|     rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size
 |     rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size
 | ||||||
| 
 | 
 | ||||||
|  | @ -655,14 +384,11 @@ void ReceiveParameter(Service::Interface* self) { | ||||||
|     rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); |     rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); | ||||||
| 
 | 
 | ||||||
|     Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); |     Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); | ||||||
| 
 |  | ||||||
|     // Clear the parameter
 |  | ||||||
|     next_parameter = boost::none; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GlanceParameter(Service::Interface* self) { | void GlanceParameter(Service::Interface* self) { | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080
 |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080
 | ||||||
|     u32 app_id = rp.Pop<u32>(); |     AppletId app_id = rp.PopEnum<AppletId>(); | ||||||
|     u32 buffer_size = rp.Pop<u32>(); |     u32 buffer_size = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     size_t static_buff_size; |     size_t static_buff_size; | ||||||
|  | @ -673,26 +399,21 @@ void GlanceParameter(Service::Interface* self) { | ||||||
|             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", |             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||||||
|             buffer_size, static_buff_size); |             buffer_size, static_buff_size); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); |     LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", static_cast<u32>(app_id), | ||||||
|  |               buffer_size); | ||||||
| 
 | 
 | ||||||
|     if (!next_parameter) { |     auto next_parameter = applet_manager->GlanceParameter(app_id); | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |  | ||||||
|         rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, |  | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (next_parameter->destination_id != app_id) { |     if (next_parameter.Failed()) { | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|         rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, |         rb.Push(next_parameter.Code()); | ||||||
|                            ErrorLevel::Status)); |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); |     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); | ||||||
|     rb.Push(RESULT_SUCCESS); // No error
 |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     rb.Push(next_parameter->sender_id); |     rb.PushEnum(next_parameter->sender_id); | ||||||
|     rb.Push(next_parameter->signal); // Signal type
 |     rb.PushEnum(next_parameter->signal); // Signal type
 | ||||||
|     ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); |     ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||||||
|     rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size
 |     rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size
 | ||||||
| 
 | 
 | ||||||
|  | @ -703,44 +424,26 @@ void GlanceParameter(Service::Interface* self) { | ||||||
|     rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); |     rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); | ||||||
| 
 | 
 | ||||||
|     Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); |     Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); | ||||||
| 
 |  | ||||||
|     // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter.
 |  | ||||||
|     if (next_parameter->signal == static_cast<u32>(SignalType::DspSleep) || |  | ||||||
|         next_parameter->signal == static_cast<u32>(SignalType::DspWakeup)) |  | ||||||
|         next_parameter = boost::none; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CancelParameter(Service::Interface* self) { | void CancelParameter(Service::Interface* self) { | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100
 |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100
 | ||||||
| 
 | 
 | ||||||
|     bool check_sender = rp.Pop<bool>(); |     bool check_sender = rp.Pop<bool>(); | ||||||
|     u32 sender_appid = rp.Pop<u32>(); |     AppletId sender_appid = rp.PopEnum<AppletId>(); | ||||||
|     bool check_receiver = rp.Pop<bool>(); |     bool check_receiver = rp.Pop<bool>(); | ||||||
|     u32 receiver_appid = rp.Pop<u32>(); |     AppletId receiver_appid = rp.PopEnum<AppletId>(); | ||||||
| 
 |  | ||||||
|     bool cancellation_success = true; |  | ||||||
| 
 |  | ||||||
|     if (!next_parameter) { |  | ||||||
|         cancellation_success = false; |  | ||||||
|     } else { |  | ||||||
|         if (check_sender && next_parameter->sender_id != sender_appid) |  | ||||||
|             cancellation_success = false; |  | ||||||
| 
 |  | ||||||
|         if (check_receiver && next_parameter->destination_id != receiver_appid) |  | ||||||
|             cancellation_success = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (cancellation_success) |  | ||||||
|         next_parameter = boost::none; |  | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
| 
 | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); // No error
 |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
|     rb.Push(cancellation_success); |     rb.Push(applet_manager->CancelParameter(check_sender, sender_appid, check_receiver, | ||||||
|  |                                             receiver_appid)); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called check_sender=%u, sender_appid=0x%08X, " |     LOG_DEBUG(Service_APT, "called check_sender=%u, sender_appid=0x%08X, " | ||||||
|                            "check_receiver=%u, receiver_appid=0x%08X", |                            "check_receiver=%u, receiver_appid=0x%08X", | ||||||
|               check_sender, sender_appid, check_receiver, receiver_appid); |               check_sender, static_cast<u32>(sender_appid), check_receiver, | ||||||
|  |               static_cast<u32>(receiver_appid)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PrepareToStartApplication(Service::Interface* self) { | void PrepareToStartApplication(Service::Interface* self) { | ||||||
|  | @ -840,38 +543,7 @@ void PrepareToStartLibraryApplet(Service::Interface* self) { | ||||||
|     LOG_DEBUG(Service_APT, "called applet_id=%08X", static_cast<u32>(applet_id)); |     LOG_DEBUG(Service_APT, "called applet_id=%08X", static_cast<u32>(applet_id)); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
| 
 |     rb.Push(applet_manager->PrepareToStartLibraryApplet(applet_id)); | ||||||
|     // The real APT service returns an error if there's a pending APT parameter when this function
 |  | ||||||
|     // is called.
 |  | ||||||
|     if (next_parameter) { |  | ||||||
|         rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, |  | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)]; |  | ||||||
| 
 |  | ||||||
|     if (slot.registered) { |  | ||||||
|         rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, |  | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); |  | ||||||
|     if (process) { |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // If we weren't able to load the native applet title, try to fallback to an HLE implementation.
 |  | ||||||
|     auto applet = HLE::Applets::Applet::Get(applet_id); |  | ||||||
|     if (applet) { |  | ||||||
|         LOG_WARNING(Service_APT, "applet has already been started id=%08X", |  | ||||||
|                     static_cast<u32>(applet_id)); |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|     } else { |  | ||||||
|         rb.Push(HLE::Applets::Applet::Create(applet_id)); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PrepareToStartNewestHomeMenu(Service::Interface* self) { | void PrepareToStartNewestHomeMenu(Service::Interface* self) { | ||||||
|  | @ -895,42 +567,15 @@ void PreloadLibraryApplet(Service::Interface* self) { | ||||||
|     LOG_DEBUG(Service_APT, "called applet_id=%08X", static_cast<u32>(applet_id)); |     LOG_DEBUG(Service_APT, "called applet_id=%08X", static_cast<u32>(applet_id)); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
| 
 |     rb.Push(applet_manager->PreloadLibraryApplet(applet_id)); | ||||||
|     const auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)]; |  | ||||||
| 
 |  | ||||||
|     if (slot.registered) { |  | ||||||
|         rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, |  | ||||||
|                            ErrorSummary::InvalidState, ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id)); |  | ||||||
|     if (process) { |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // If we weren't able to load the native applet title, try to fallback to an HLE implementation.
 |  | ||||||
|     auto applet = HLE::Applets::Applet::Get(applet_id); |  | ||||||
|     if (applet) { |  | ||||||
|         LOG_WARNING(Service_APT, "applet has already been started id=%08X", |  | ||||||
|                     static_cast<u32>(applet_id)); |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|     } else { |  | ||||||
|         rb.Push(HLE::Applets::Applet::Create(applet_id)); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FinishPreloadingLibraryApplet(Service::Interface* self) { | void FinishPreloadingLibraryApplet(Service::Interface* self) { | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x17, 1, 0); // 0x00170040
 |     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x17, 1, 0); // 0x00170040
 | ||||||
|     AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); |     AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): This function should fail depending on the applet preparation state.
 |  | ||||||
|     auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)]; |  | ||||||
|     slot.loaded = true; |  | ||||||
| 
 |  | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(applet_manager->FinishPreloadingLibraryApplet(applet_id)); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called applet_id=%03X", static_cast<u32>(applet_id)); |     LOG_WARNING(Service_APT, "(STUBBED) called applet_id=%03X", static_cast<u32>(applet_id)); | ||||||
| } | } | ||||||
|  | @ -947,26 +592,11 @@ void StartLibraryApplet(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
| 
 | 
 | ||||||
|     // Send the Wakeup signal to the applet
 |     std::vector<u8> buffer(buffer_size); | ||||||
|     MessageParameter param; |     Memory::ReadBlock(buffer_addr, buffer.data(), buffer.size()); | ||||||
|     param.destination_id = static_cast<u32>(applet_id); |  | ||||||
|     param.sender_id = static_cast<u32>(AppletId::Application); |  | ||||||
|     param.object = Kernel::g_handle_table.GetGeneric(handle); |  | ||||||
|     param.signal = static_cast<u32>(SignalType::Wakeup); |  | ||||||
|     param.buffer.resize(buffer_size); |  | ||||||
|     Memory::ReadBlock(buffer_addr, param.buffer.data(), param.buffer.size()); |  | ||||||
|     SendParameter(param); |  | ||||||
| 
 | 
 | ||||||
|     // In case the applet is being HLEd, attempt to communicate with it.
 |     rb.Push(applet_manager->StartLibraryApplet(applet_id, Kernel::g_handle_table.GetGeneric(handle), | ||||||
|     if (auto applet = HLE::Applets::Applet::Get(applet_id)) { |                                                buffer)); | ||||||
|         AppletStartupParameter parameter; |  | ||||||
|         parameter.object = Kernel::g_handle_table.GetGeneric(handle); |  | ||||||
|         parameter.buffer.resize(buffer_size); |  | ||||||
|         Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); |  | ||||||
|         rb.Push(applet->Start(parameter)); |  | ||||||
|     } else { |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CancelLibraryApplet(Service::Interface* self) { | void CancelLibraryApplet(Service::Interface* self) { | ||||||
|  | @ -1006,48 +636,19 @@ void GetAppletInfo(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called appid=%u", static_cast<u32>(app_id)); |     LOG_DEBUG(Service_APT, "called appid=%u", static_cast<u32>(app_id)); | ||||||
| 
 | 
 | ||||||
|     const auto* slot = GetAppletSlotData(app_id); |     auto info = applet_manager->GetAppletInfo(app_id); | ||||||
| 
 |     if (info.Failed()) { | ||||||
|     if (slot == nullptr || !slot->registered) { |  | ||||||
|         // See if there's an HLE applet and try to use it before erroring out.
 |  | ||||||
|         auto hle_applet = HLE::Applets::Applet::Get(app_id); |  | ||||||
|         if (hle_applet == nullptr) { |  | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|             rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, |         rb.Push(info.Code()); | ||||||
|                                ErrorSummary::NotFound, ErrorLevel::Status)); |     } else { | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // TODO(Subv): Get the title id for the current applet and write it in the response[2-3]
 |  | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|         u64 title_id = 0; |         rb.Push(info->title_id); | ||||||
|         rb.Push(title_id); |         rb.Push(static_cast<u8>(info->media_type)); | ||||||
|         rb.Push(static_cast<u32>(Service::FS::MediaType::NAND)); |         rb.Push(info->registered); | ||||||
|         rb.Push(true);   // Registered
 |         rb.Push(info->loaded); | ||||||
|         rb.Push(true);   // Loaded
 |         rb.Push(info->attributes); | ||||||
|         rb.Push<u32>(0); // Applet Attributes
 |  | ||||||
|         LOG_WARNING(Service_APT, "Using HLE applet info for applet %03X", static_cast<u32>(app_id)); |  | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     if (app_id == AppletId::Application) { |  | ||||||
|         // TODO(Subv): Implement this once Application launching is implemented
 |  | ||||||
|         LOG_ERROR(Service_APT, "Unimplemented GetAppletInfo(Application)"); |  | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |  | ||||||
|         rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, |  | ||||||
|                            ErrorLevel::Status)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); |  | ||||||
|     rb.Push(RESULT_SUCCESS); |  | ||||||
|     rb.Push(GetTitleIdForApplet(app_id)); |  | ||||||
|     // Note: The NS service hardcodes this to NAND for all applets except the Application applet.
 |  | ||||||
|     rb.Push(static_cast<u8>(Service::FS::MediaType::NAND)); |  | ||||||
|     rb.Push(slot->registered); |  | ||||||
|     rb.Push(slot->loaded); |  | ||||||
|     rb.Push(slot->attributes.raw); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetStartupArgument(Service::Interface* self) { | void GetStartupArgument(Service::Interface* self) { | ||||||
|  | @ -1213,7 +814,7 @@ void Init() { | ||||||
|     AddService(new APT_S_Interface); |     AddService(new APT_S_Interface); | ||||||
|     AddService(new APT_U_Interface); |     AddService(new APT_U_Interface); | ||||||
| 
 | 
 | ||||||
|     HLE::Applets::Init(); |     applet_manager = std::make_shared<AppletManager>(); | ||||||
| 
 | 
 | ||||||
|     using Kernel::MemoryPermission; |     using Kernel::MemoryPermission; | ||||||
|     shared_font_mem = |     shared_font_mem = | ||||||
|  | @ -1227,19 +828,6 @@ void Init() { | ||||||
|     unknown_ns_state_field = 0; |     unknown_ns_state_field = 0; | ||||||
|     screen_capture_post_permission = |     screen_capture_post_permission = | ||||||
|         ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
 |         ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
 | ||||||
| 
 |  | ||||||
|     for (size_t slot = 0; slot < applet_slots.size(); ++slot) { |  | ||||||
|         auto& slot_data = applet_slots[slot]; |  | ||||||
|         slot_data.slot = static_cast<AppletSlot>(slot); |  | ||||||
|         slot_data.applet_id = AppletId::None; |  | ||||||
|         slot_data.attributes.raw = 0; |  | ||||||
|         slot_data.registered = false; |  | ||||||
|         slot_data.loaded = false; |  | ||||||
|         slot_data.notification_event = |  | ||||||
|             Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); |  | ||||||
|         slot_data.parameter_event = |  | ||||||
|             Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|  | @ -1248,18 +836,7 @@ void Shutdown() { | ||||||
|     shared_font_relocated = false; |     shared_font_relocated = false; | ||||||
|     lock = nullptr; |     lock = nullptr; | ||||||
| 
 | 
 | ||||||
|     for (auto& slot : applet_slots) { |     applet_manager = nullptr; | ||||||
|         slot.registered = false; |  | ||||||
|         slot.notification_event = nullptr; |  | ||||||
|         slot.parameter_event = nullptr; |  | ||||||
|         slot.loaded = false; |  | ||||||
|         slot.attributes.raw = 0; |  | ||||||
|         slot.applet_id = AppletId::None; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     next_parameter = boost::none; |  | ||||||
| 
 |  | ||||||
|     HLE::Applets::Shutdown(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace APT
 | } // namespace APT
 | ||||||
|  |  | ||||||
|  | @ -19,21 +19,6 @@ namespace APT { | ||||||
| /// Each APT service can only have up to 2 sessions connected at the same time.
 | /// Each APT service can only have up to 2 sessions connected at the same time.
 | ||||||
| static const u32 MaxAPTSessions = 2; | static const u32 MaxAPTSessions = 2; | ||||||
| 
 | 
 | ||||||
| /// Holds information about the parameters used in Send/Glance/ReceiveParameter
 |  | ||||||
| struct MessageParameter { |  | ||||||
|     u32 sender_id = 0; |  | ||||||
|     u32 destination_id = 0; |  | ||||||
|     u32 signal = 0; |  | ||||||
|     Kernel::SharedPtr<Kernel::Object> object = nullptr; |  | ||||||
|     std::vector<u8> buffer; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /// Holds information about the parameters used in StartLibraryApplet
 |  | ||||||
| struct AppletStartupParameter { |  | ||||||
|     Kernel::SharedPtr<Kernel::Object> object = nullptr; |  | ||||||
|     std::vector<u8> buffer; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /// Used by the application to pass information about the current framebuffer to applets.
 | /// Used by the application to pass information about the current framebuffer to applets.
 | ||||||
| struct CaptureBufferInfo { | struct CaptureBufferInfo { | ||||||
|     u32_le size; |     u32_le size; | ||||||
|  | @ -48,65 +33,6 @@ struct CaptureBufferInfo { | ||||||
| }; | }; | ||||||
| static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has incorrect size"); | static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has incorrect size"); | ||||||
| 
 | 
 | ||||||
| /// Signals used by APT functions
 |  | ||||||
| enum class SignalType : u32 { |  | ||||||
|     None = 0x0, |  | ||||||
|     Wakeup = 0x1, |  | ||||||
|     Request = 0x2, |  | ||||||
|     Response = 0x3, |  | ||||||
|     Exit = 0x4, |  | ||||||
|     Message = 0x5, |  | ||||||
|     HomeButtonSingle = 0x6, |  | ||||||
|     HomeButtonDouble = 0x7, |  | ||||||
|     DspSleep = 0x8, |  | ||||||
|     DspWakeup = 0x9, |  | ||||||
|     WakeupByExit = 0xA, |  | ||||||
|     WakeupByPause = 0xB, |  | ||||||
|     WakeupByCancel = 0xC, |  | ||||||
|     WakeupByCancelAll = 0xD, |  | ||||||
|     WakeupByPowerButtonClick = 0xE, |  | ||||||
|     WakeupToJumpHome = 0xF, |  | ||||||
|     RequestForSysApplet = 0x10, |  | ||||||
|     WakeupToLaunchApplication = 0x11, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /// App Id's used by APT functions
 |  | ||||||
| enum class AppletId : u32 { |  | ||||||
|     None = 0, |  | ||||||
|     AnySystemApplet = 0x100, |  | ||||||
|     HomeMenu = 0x101, |  | ||||||
|     AlternateMenu = 0x103, |  | ||||||
|     Camera = 0x110, |  | ||||||
|     FriendList = 0x112, |  | ||||||
|     GameNotes = 0x113, |  | ||||||
|     InternetBrowser = 0x114, |  | ||||||
|     InstructionManual = 0x115, |  | ||||||
|     Notifications = 0x116, |  | ||||||
|     Miiverse = 0x117, |  | ||||||
|     MiiversePost = 0x118, |  | ||||||
|     AmiiboSettings = 0x119, |  | ||||||
|     AnySysLibraryApplet = 0x200, |  | ||||||
|     SoftwareKeyboard1 = 0x201, |  | ||||||
|     Ed1 = 0x202, |  | ||||||
|     PnoteApp = 0x204, |  | ||||||
|     SnoteApp = 0x205, |  | ||||||
|     Error = 0x206, |  | ||||||
|     Mint = 0x207, |  | ||||||
|     Extrapad = 0x208, |  | ||||||
|     Memolib = 0x209, |  | ||||||
|     Application = 0x300, |  | ||||||
|     Tiger = 0x301, |  | ||||||
|     AnyLibraryApplet = 0x400, |  | ||||||
|     SoftwareKeyboard2 = 0x401, |  | ||||||
|     Ed2 = 0x402, |  | ||||||
|     PnoteApp2 = 0x404, |  | ||||||
|     SnoteApp2 = 0x405, |  | ||||||
|     Error2 = 0x406, |  | ||||||
|     Mint2 = 0x407, |  | ||||||
|     Extrapad2 = 0x408, |  | ||||||
|     Memolib2 = 0x409, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| enum class StartupArgumentType : u32 { | enum class StartupArgumentType : u32 { | ||||||
|     OtherApp = 0, |     OtherApp = 0, | ||||||
|     Restart = 1, |     Restart = 1, | ||||||
|  | @ -120,16 +46,6 @@ enum class ScreencapPostPermission : u32 { | ||||||
|     DisableScreenshotPostingToMiiverse = 3 |     DisableScreenshotPostingToMiiverse = 3 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| namespace ErrCodes { |  | ||||||
| enum { |  | ||||||
|     ParameterPresent = 2, |  | ||||||
|     InvalidAppletSlot = 4, |  | ||||||
| }; |  | ||||||
| } // namespace ErrCodes
 |  | ||||||
| 
 |  | ||||||
| /// Send a parameter to the currently-running application, which will read it via ReceiveParameter
 |  | ||||||
| void SendParameter(const MessageParameter& parameter); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * APT::Initialize service function |  * APT::Initialize service function | ||||||
|  * Service function that initializes the APT process for the running application |  * Service function that initializes the APT process for the running application | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								src/core/hle/service/apt/errors.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/core/hle/service/apt/errors.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | // Copyright 2018 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | namespace Service { | ||||||
|  | namespace APT { | ||||||
|  | namespace ErrCodes { | ||||||
|  | enum { | ||||||
|  |     ParameterPresent = 2, | ||||||
|  |     InvalidAppletSlot = 4, | ||||||
|  | }; | ||||||
|  | } // namespace ErrCodes
 | ||||||
|  | } // namespace APT
 | ||||||
|  | } // namespace Service
 | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
|  | #include "core/hle/service/fs/archive.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue