mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	service/apt: Add and implement more service commands. (#6721)
* service/apt: Add and implement more service commands. * service/apt: Implement power button. * Address review comments and fix GetApplicationRunningMode bug.
This commit is contained in:
		
							parent
							
								
									51996c54f0
								
							
						
					
					
						commit
						bb364d9bc0
					
				
					 31 changed files with 939 additions and 221 deletions
				
			
		|  | @ -29,7 +29,7 @@ Config::~Config() { | ||||||
| const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { | const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { | ||||||
|     Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G, |     Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G, | ||||||
|     Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N, |     Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N, | ||||||
|     Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, |     Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ | const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ | ||||||
|  |  | ||||||
|  | @ -162,7 +162,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|         ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, |         ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, | ||||||
|         ui->buttonL,      ui->buttonR,        ui->buttonStart,    ui->buttonSelect, |         ui->buttonL,      ui->buttonR,        ui->buttonStart,    ui->buttonSelect, | ||||||
|         ui->buttonDebug,  ui->buttonGpio14,   ui->buttonZL,       ui->buttonZR, |         ui->buttonDebug,  ui->buttonGpio14,   ui->buttonZL,       ui->buttonZR, | ||||||
|         ui->buttonHome, |         ui->buttonHome,   ui->buttonPower, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     analog_map_buttons = {{ |     analog_map_buttons = {{ | ||||||
|  |  | ||||||
|  | @ -305,6 +305,24 @@ | ||||||
|          </layout> |          </layout> | ||||||
|         </item> |         </item> | ||||||
|         <item row="1" column="1"> |         <item row="1" column="1"> | ||||||
|  |          <layout class="QVBoxLayout" name="verticalLayout_34"> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QLabel" name="label_37"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Power:</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QPushButton" name="buttonPower"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string/> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="2" column="0"> | ||||||
|          <layout class="QVBoxLayout" name="verticalLayout_28"> |          <layout class="QVBoxLayout" name="verticalLayout_28"> | ||||||
|           <item> |           <item> | ||||||
|            <widget class="QLabel" name="label_36"> |            <widget class="QLabel" name="label_36"> | ||||||
|  | @ -340,7 +358,7 @@ | ||||||
|           </item> |           </item> | ||||||
|          </layout> |          </layout> | ||||||
|         </item> |         </item> | ||||||
|         <item row="2" column="0"> |         <item row="3" column="0"> | ||||||
|          <layout class="QVBoxLayout" name="verticalLayout_32"> |          <layout class="QVBoxLayout" name="verticalLayout_32"> | ||||||
|           <item> |           <item> | ||||||
|            <widget class="QLabel" name="label_40"> |            <widget class="QLabel" name="label_40"> | ||||||
|  |  | ||||||
|  | @ -100,13 +100,14 @@ enum Values { | ||||||
|     ZR, |     ZR, | ||||||
| 
 | 
 | ||||||
|     Home, |     Home, | ||||||
|  |     Power, | ||||||
| 
 | 
 | ||||||
|     NumButtons, |     NumButtons, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| constexpr int BUTTON_HID_BEGIN = A; | constexpr int BUTTON_HID_BEGIN = A; | ||||||
| constexpr int BUTTON_IR_BEGIN = ZL; | constexpr int BUTTON_IR_BEGIN = ZL; | ||||||
| constexpr int BUTTON_NS_BEGIN = Home; | constexpr int BUTTON_NS_BEGIN = Power; | ||||||
| 
 | 
 | ||||||
| constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN; | constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN; | ||||||
| constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN; | constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN; | ||||||
|  | @ -134,6 +135,7 @@ static const std::array<const char*, NumButtons> mapping = {{ | ||||||
|     "button_zl", |     "button_zl", | ||||||
|     "button_zr", |     "button_zr", | ||||||
|     "button_home", |     "button_home", | ||||||
|  |     "button_power", | ||||||
| }}; | }}; | ||||||
| 
 | 
 | ||||||
| } // namespace NativeButton
 | } // namespace NativeButton
 | ||||||
|  |  | ||||||
|  | @ -259,14 +259,13 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st | ||||||
|         LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |         LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); | ||||||
|         return ResultStatus::ErrorGetLoader; |         return ResultStatus::ErrorGetLoader; | ||||||
|     } |     } | ||||||
|     std::pair<std::optional<u32>, Loader::ResultStatus> system_mode = |  | ||||||
|         app_loader->LoadKernelSystemMode(); |  | ||||||
| 
 | 
 | ||||||
|     if (system_mode.second != Loader::ResultStatus::Success) { |     auto memory_mode = app_loader->LoadKernelMemoryMode(); | ||||||
|  |     if (memory_mode.second != Loader::ResultStatus::Success) { | ||||||
|         LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", |         LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", | ||||||
|                      static_cast<int>(system_mode.second)); |                      static_cast<int>(memory_mode.second)); | ||||||
| 
 | 
 | ||||||
|         switch (system_mode.second) { |         switch (memory_mode.second) { | ||||||
|         case Loader::ResultStatus::ErrorEncrypted: |         case Loader::ResultStatus::ErrorEncrypted: | ||||||
|             return ResultStatus::ErrorLoader_ErrorEncrypted; |             return ResultStatus::ErrorLoader_ErrorEncrypted; | ||||||
|         case Loader::ResultStatus::ErrorInvalidFormat: |         case Loader::ResultStatus::ErrorInvalidFormat: | ||||||
|  | @ -278,15 +277,15 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ASSERT(system_mode.first); |     ASSERT(memory_mode.first); | ||||||
|     auto n3ds_mode = app_loader->LoadKernelN3dsMode(); |     auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities(); | ||||||
|     ASSERT(n3ds_mode.first); |     ASSERT(n3ds_hw_caps.first); | ||||||
|     u32 num_cores = 2; |     u32 num_cores = 2; | ||||||
|     if (Settings::values.is_new_3ds) { |     if (Settings::values.is_new_3ds) { | ||||||
|         num_cores = 4; |         num_cores = 4; | ||||||
|     } |     } | ||||||
|     ResultStatus init_result{ |     ResultStatus init_result{ | ||||||
|         Init(emu_window, secondary_window, *system_mode.first, *n3ds_mode.first, num_cores)}; |         Init(emu_window, secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores)}; | ||||||
|     if (init_result != ResultStatus::Success) { |     if (init_result != ResultStatus::Success) { | ||||||
|         LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", |         LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", | ||||||
|                      static_cast<u32>(init_result)); |                      static_cast<u32>(init_result)); | ||||||
|  | @ -363,8 +362,9 @@ void System::Reschedule() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, | ||||||
|                                   Frontend::EmuWindow* secondary_window, u32 system_mode, |                                   Frontend::EmuWindow* secondary_window, | ||||||
|                                   u8 n3ds_mode, u32 num_cores) { |                                   Kernel::MemoryMode memory_mode, | ||||||
|  |                                   const Kernel::New3dsHwCapabilities& n3ds_hw_caps, u32 num_cores) { | ||||||
|     LOG_DEBUG(HW_Memory, "initialized OK"); |     LOG_DEBUG(HW_Memory, "initialized OK"); | ||||||
| 
 | 
 | ||||||
|     memory = std::make_unique<Memory::MemorySystem>(); |     memory = std::make_unique<Memory::MemorySystem>(); | ||||||
|  | @ -372,7 +372,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, | ||||||
|     timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue()); |     timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue()); | ||||||
| 
 | 
 | ||||||
|     kernel = std::make_unique<Kernel::KernelSystem>( |     kernel = std::make_unique<Kernel::KernelSystem>( | ||||||
|         *memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode); |         *memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps); | ||||||
| 
 | 
 | ||||||
|     exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores); |     exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores); | ||||||
|     cpu_cores.reserve(num_cores); |     cpu_cores.reserve(num_cores); | ||||||
|  | @ -673,10 +673,10 @@ void System::serialize(Archive& ar, const unsigned int file_version) { | ||||||
|         Shutdown(true); |         Shutdown(true); | ||||||
| 
 | 
 | ||||||
|         // Re-initialize everything like it was before
 |         // Re-initialize everything like it was before
 | ||||||
|         auto system_mode = this->app_loader->LoadKernelSystemMode(); |         auto memory_mode = this->app_loader->LoadKernelMemoryMode(); | ||||||
|         auto n3ds_mode = this->app_loader->LoadKernelN3dsMode(); |         auto n3ds_hw_caps = this->app_loader->LoadNew3dsHwCapabilities(); | ||||||
|         [[maybe_unused]] const System::ResultStatus result = Init( |         [[maybe_unused]] const System::ResultStatus result = Init( | ||||||
|             *m_emu_window, m_secondary_window, *system_mode.first, *n3ds_mode.first, num_cores); |             *m_emu_window, m_secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // flush on save, don't flush on load
 |     // flush on save, don't flush on load
 | ||||||
|  |  | ||||||
|  | @ -342,8 +342,10 @@ private: | ||||||
|      * @return ResultStatus code, indicating if the operation succeeded. |      * @return ResultStatus code, indicating if the operation succeeded. | ||||||
|      */ |      */ | ||||||
|     [[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window, |     [[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window, | ||||||
|                                     Frontend::EmuWindow* secondary_window, u32 system_mode, |                                     Frontend::EmuWindow* secondary_window, | ||||||
|                                     u8 n3ds_mode, u32 num_cores); |                                     Kernel::MemoryMode memory_mode, | ||||||
|  |                                     const Kernel::New3dsHwCapabilities& n3ds_hw_caps, | ||||||
|  |                                     u32 num_cores); | ||||||
| 
 | 
 | ||||||
|     /// Reschedule the core emulation
 |     /// Reschedule the core emulation
 | ||||||
|     void Reschedule(); |     void Reschedule(); | ||||||
|  |  | ||||||
|  | @ -165,7 +165,11 @@ struct ExHeader_StorageInfo { | ||||||
| struct ExHeader_ARM11_SystemLocalCaps { | struct ExHeader_ARM11_SystemLocalCaps { | ||||||
|     u64_le program_id; |     u64_le program_id; | ||||||
|     u32_le core_version; |     u32_le core_version; | ||||||
|     u8 reserved_flag; |     union { | ||||||
|  |         u8 n3ds_cpu_flags; | ||||||
|  |         BitField<0, 1, u8> enable_l2_cache; | ||||||
|  |         BitField<1, 1, u8> enable_804MHz_cpu; | ||||||
|  |     }; | ||||||
|     u8 n3ds_mode; |     u8 n3ds_mode; | ||||||
|     union { |     union { | ||||||
|         u8 flags0; |         u8 flags0; | ||||||
|  |  | ||||||
|  | @ -23,13 +23,15 @@ namespace Kernel { | ||||||
| 
 | 
 | ||||||
| /// Initialize the kernel
 | /// Initialize the kernel
 | ||||||
| KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, | KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, | ||||||
|                            std::function<void()> prepare_reschedule_callback, u32 system_mode, |                            std::function<void()> prepare_reschedule_callback, | ||||||
|                            u32 num_cores, u8 n3ds_mode) |                            MemoryMode memory_mode, u32 num_cores, | ||||||
|  |                            const New3dsHwCapabilities& n3ds_hw_caps) | ||||||
|     : memory(memory), timing(timing), |     : memory(memory), timing(timing), | ||||||
|       prepare_reschedule_callback(std::move(prepare_reschedule_callback)) { |       prepare_reschedule_callback(std::move(prepare_reschedule_callback)), memory_mode(memory_mode), | ||||||
|  |       n3ds_hw_caps(n3ds_hw_caps) { | ||||||
|     std::generate(memory_regions.begin(), memory_regions.end(), |     std::generate(memory_regions.begin(), memory_regions.end(), | ||||||
|                   [] { return std::make_shared<MemoryRegionInfo>(); }); |                   [] { return std::make_shared<MemoryRegionInfo>(); }); | ||||||
|     MemoryInit(system_mode, n3ds_mode); |     MemoryInit(memory_mode, n3ds_hw_caps.memory_mode); | ||||||
| 
 | 
 | ||||||
|     resource_limits = std::make_unique<ResourceLimitList>(*this); |     resource_limits = std::make_unique<ResourceLimitList>(*this); | ||||||
|     for (u32 core_id = 0; core_id < num_cores; ++core_id) { |     for (u32 core_id = 0; core_id < num_cores; ++core_id) { | ||||||
|  | @ -176,6 +178,8 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version) { | ||||||
|     ar& shared_page_handler; |     ar& shared_page_handler; | ||||||
|     ar& stored_processes; |     ar& stored_processes; | ||||||
|     ar& next_thread_id; |     ar& next_thread_id; | ||||||
|  |     ar& memory_mode; | ||||||
|  |     ar& n3ds_hw_caps; | ||||||
|     // Deliberately don't include debugger info to allow debugging through loads
 |     // Deliberately don't include debugger info to allow debugging through loads
 | ||||||
| 
 | 
 | ||||||
|     if (Archive::is_loading::value) { |     if (Archive::is_loading::value) { | ||||||
|  |  | ||||||
|  | @ -97,11 +97,44 @@ union CoreVersion { | ||||||
|     BitField<24, 8, u32> major; |     BitField<24, 8, u32> major; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /// Common memory memory modes.
 | ||||||
|  | enum class MemoryMode : u8 { | ||||||
|  |     Prod = 0, ///< 64MB app memory
 | ||||||
|  |     Dev1 = 2, ///< 96MB app memory
 | ||||||
|  |     Dev2 = 3, ///< 80MB app memory
 | ||||||
|  |     Dev3 = 4, ///< 72MB app memory
 | ||||||
|  |     Dev4 = 5, ///< 32MB app memory
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// New 3DS memory modes.
 | ||||||
|  | enum class New3dsMemoryMode : u8 { | ||||||
|  |     Legacy = 0,  ///< Use Old 3DS system mode.
 | ||||||
|  |     NewProd = 1, ///< 124MB app memory
 | ||||||
|  |     NewDev1 = 2, ///< 178MB app memory
 | ||||||
|  |     NewDev2 = 3, ///< 124MB app memory
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// Structure containing N3DS hardware capability flags.
 | ||||||
|  | struct New3dsHwCapabilities { | ||||||
|  |     bool enable_l2_cache;         ///< Whether extra L2 cache should be enabled.
 | ||||||
|  |     bool enable_804MHz_cpu;       ///< Whether the CPU should run at 804MHz.
 | ||||||
|  |     New3dsMemoryMode memory_mode; ///< The New 3DS memory mode.
 | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     template <class Archive> | ||||||
|  |     void serialize(Archive& ar, const unsigned int) { | ||||||
|  |         ar& enable_l2_cache; | ||||||
|  |         ar& enable_804MHz_cpu; | ||||||
|  |         ar& memory_mode; | ||||||
|  |     } | ||||||
|  |     friend class boost::serialization::access; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class KernelSystem { | class KernelSystem { | ||||||
| public: | public: | ||||||
|     explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, |     explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, | ||||||
|                           std::function<void()> prepare_reschedule_callback, u32 system_mode, |                           std::function<void()> prepare_reschedule_callback, MemoryMode memory_mode, | ||||||
|                           u32 num_cores, u8 n3ds_mode); |                           u32 num_cores, const New3dsHwCapabilities& n3ds_hw_caps); | ||||||
|     ~KernelSystem(); |     ~KernelSystem(); | ||||||
| 
 | 
 | ||||||
|     using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>; |     using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>; | ||||||
|  | @ -279,6 +312,14 @@ public: | ||||||
| 
 | 
 | ||||||
|     void ResetThreadIDs(); |     void ResetThreadIDs(); | ||||||
| 
 | 
 | ||||||
|  |     MemoryMode GetMemoryMode() const { | ||||||
|  |         return memory_mode; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const New3dsHwCapabilities& GetNew3dsHwCapabilities() const { | ||||||
|  |         return n3ds_hw_caps; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
 |     /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
 | ||||||
|     std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports; |     std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports; | ||||||
| 
 | 
 | ||||||
|  | @ -289,7 +330,7 @@ public: | ||||||
|     Core::Timing& timing; |     Core::Timing& timing; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void MemoryInit(u32 mem_type, u8 n3ds_mode); |     void MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode); | ||||||
| 
 | 
 | ||||||
|     std::function<void()> prepare_reschedule_callback; |     std::function<void()> prepare_reschedule_callback; | ||||||
| 
 | 
 | ||||||
|  | @ -324,6 +365,9 @@ private: | ||||||
| 
 | 
 | ||||||
|     u32 next_thread_id; |     u32 next_thread_id; | ||||||
| 
 | 
 | ||||||
|  |     MemoryMode memory_mode; | ||||||
|  |     New3dsHwCapabilities n3ds_hw_caps; | ||||||
|  | 
 | ||||||
|     friend class boost::serialization::access; |     friend class boost::serialization::access; | ||||||
|     template <class Archive> |     template <class Archive> | ||||||
|     void serialize(Archive& ar, const unsigned int file_version); |     void serialize(Archive& ar, const unsigned int file_version); | ||||||
|  |  | ||||||
|  | @ -37,29 +37,20 @@ static const u32 memory_region_sizes[8][3] = { | ||||||
|     {0x0B200000, 0x02E00000, 0x02000000}, // 7
 |     {0x0B200000, 0x02E00000, 0x02000000}, // 7
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| namespace MemoryMode { | void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode) { | ||||||
| enum N3DSMode : u8 { |  | ||||||
|     Mode6 = 1, |  | ||||||
|     Mode7 = 2, |  | ||||||
|     Mode6_2 = 3, |  | ||||||
| }; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) { |  | ||||||
|     ASSERT(mem_type != 1); |  | ||||||
| 
 |  | ||||||
|     const bool is_new_3ds = Settings::values.is_new_3ds.GetValue(); |     const bool is_new_3ds = Settings::values.is_new_3ds.GetValue(); | ||||||
|     u32 reported_mem_type = mem_type; |     u32 mem_type_index = static_cast<u32>(memory_mode); | ||||||
|  |     u32 reported_mem_type = static_cast<u32>(memory_mode); | ||||||
|     if (is_new_3ds) { |     if (is_new_3ds) { | ||||||
|         if (n3ds_mode == MemoryMode::Mode6 || n3ds_mode == MemoryMode::Mode6_2) { |         if (n3ds_mode == New3dsMemoryMode::NewProd || n3ds_mode == New3dsMemoryMode::NewDev2) { | ||||||
|             mem_type = 6; |             mem_type_index = 6; | ||||||
|             reported_mem_type = 6; |             reported_mem_type = 6; | ||||||
|         } else if (n3ds_mode == MemoryMode::Mode7) { |         } else if (n3ds_mode == New3dsMemoryMode::NewDev1) { | ||||||
|             mem_type = 7; |             mem_type_index = 7; | ||||||
|             reported_mem_type = 7; |             reported_mem_type = 7; | ||||||
|         } else { |         } else { | ||||||
|             // On the N3ds, all O3ds configurations (<=5) are forced to 6 instead.
 |             // On the N3ds, all O3ds configurations (<=5) are forced to 6 instead.
 | ||||||
|             mem_type = 6; |             mem_type_index = 6; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -67,7 +58,7 @@ void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) { | ||||||
|     // the sizes specified in the memory_region_sizes table.
 |     // the sizes specified in the memory_region_sizes table.
 | ||||||
|     VAddr base = 0; |     VAddr base = 0; | ||||||
|     for (int i = 0; i < 3; ++i) { |     for (int i = 0; i < 3; ++i) { | ||||||
|         memory_regions[i]->Reset(base, memory_region_sizes[mem_type][i]); |         memory_regions[i]->Reset(base, memory_region_sizes[mem_type_index][i]); | ||||||
| 
 | 
 | ||||||
|         base += memory_regions[i]->size; |         base += memory_regions[i]->size; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -521,6 +521,11 @@ InstallStatus InstallFromNus(u64 title_id, int version) { | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u64 GetTitleUpdateId(u64 title_id) { | ||||||
|  |     // Real services seem to just discard and replace the whole high word.
 | ||||||
|  |     return (title_id & 0xFFFFFFFF) | (static_cast<u64>(TID_HIGH_UPDATE) << 32); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Service::FS::MediaType GetTitleMediaType(u64 titleId) { | Service::FS::MediaType GetTitleMediaType(u64 titleId) { | ||||||
|     u16 platform = static_cast<u16>(titleId >> 48); |     u16 platform = static_cast<u16>(titleId >> 48); | ||||||
|     u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF); |     u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF); | ||||||
|  |  | ||||||
|  | @ -118,6 +118,13 @@ InstallStatus InstallCIA(const std::string& path, | ||||||
|  */ |  */ | ||||||
| InstallStatus InstallFromNus(u64 title_id, int version = -1); | InstallStatus InstallFromNus(u64 title_id, int version = -1); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get the update title ID for a title | ||||||
|  |  * @param titleId the title ID | ||||||
|  |  * @returns The update title ID | ||||||
|  |  */ | ||||||
|  | u64 GetTitleUpdateId(u64 title_id); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Get the mediatype for an installed title |  * Get the mediatype for an installed title | ||||||
|  * @param titleId the installed title ID |  * @param titleId the installed title ID | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager) | ||||||
| namespace Service::APT { | namespace Service::APT { | ||||||
| 
 | 
 | ||||||
| /// The interval at which the home button update callback will be called, 16.6ms
 | /// The interval at which the home button update callback will be called, 16.6ms
 | ||||||
| static constexpr u64 home_button_update_interval_us = 16666; | static constexpr u64 button_update_interval_us = 16666; | ||||||
| 
 | 
 | ||||||
| struct AppletTitleData { | struct AppletTitleData { | ||||||
|     // There are two possible applet ids for each applet.
 |     // There are two possible applet ids for each applet.
 | ||||||
|  | @ -407,11 +407,56 @@ ResultCode AppletManager::Enable(AppletAttributes attributes) { | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultCode AppletManager::Finalize(AppletId app_id) { | ||||||
|  |     auto slot = GetAppletSlotFromId(app_id); | ||||||
|  |     if (slot == AppletSlot::Error) { | ||||||
|  |         return {ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||||||
|  |                 ErrorLevel::Status}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto slot_data = GetAppletSlot(slot); | ||||||
|  |     slot_data->Reset(); | ||||||
|  | 
 | ||||||
|  |     auto inactive = active_slot == AppletSlot::Error; | ||||||
|  |     if (!inactive) { | ||||||
|  |         auto active_slot_data = GetAppletSlot(active_slot); | ||||||
|  |         inactive = active_slot_data->applet_id == AppletId::None || | ||||||
|  |                    active_slot_data->attributes.applet_pos.Value() == AppletPos::Invalid; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (inactive) { | ||||||
|  |         active_slot = GetAppletSlotFromPos(AppletPos::System); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u32 AppletManager::CountRegisteredApplet() { | ||||||
|  |     return static_cast<u32>(std::count_if(applet_slots.begin(), applet_slots.end(), | ||||||
|  |                                           [](auto& slot_data) { return slot_data.registered; })); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool AppletManager::IsRegistered(AppletId app_id) { | bool AppletManager::IsRegistered(AppletId app_id) { | ||||||
|     auto slot = GetAppletSlotFromId(app_id); |     auto slot = GetAppletSlotFromId(app_id); | ||||||
|     return slot != AppletSlot::Error && GetAppletSlot(slot)->registered; |     return slot != AppletSlot::Error && GetAppletSlot(slot)->registered; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultVal<AppletAttributes> AppletManager::GetAttribute(AppletId app_id) { | ||||||
|  |     auto slot = GetAppletSlotFromId(app_id); | ||||||
|  |     if (slot == AppletSlot::Error) { | ||||||
|  |         return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||||||
|  |                           ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto slot_data = GetAppletSlot(slot); | ||||||
|  |     if (!slot_data->registered) { | ||||||
|  |         return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||||||
|  |                           ErrorLevel::Status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return slot_data->attributes; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ResultVal<Notification> AppletManager::InquireNotification(AppletId app_id) { | ResultVal<Notification> AppletManager::InquireNotification(AppletId app_id) { | ||||||
|     auto slot = GetAppletSlotFromId(app_id); |     auto slot = GetAppletSlotFromId(app_id); | ||||||
|     if (slot != AppletSlot::Error) { |     if (slot != AppletSlot::Error) { | ||||||
|  | @ -441,6 +486,15 @@ ResultCode AppletManager::SendNotification(Notification notification) { | ||||||
|             ErrorLevel::Status}; |             ErrorLevel::Status}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AppletManager::SendNotificationToAll(Notification notification) { | ||||||
|  |     for (auto& slot_data : applet_slots) { | ||||||
|  |         if (slot_data.registered) { | ||||||
|  |             slot_data.notification = notification; | ||||||
|  |             slot_data.notification_event->Signal(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { | ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { | ||||||
|     // The real APT service returns an error if there's a pending APT parameter when this function
 |     // The real APT service returns an error if there's a pending APT parameter when this function
 | ||||||
|     // is called.
 |     // is called.
 | ||||||
|  | @ -594,6 +648,71 @@ ResultCode AppletManager::CancelLibraryApplet(bool app_exiting) { | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultCode AppletManager::SendDspSleep(AppletId from_applet_id, | ||||||
|  |                                        std::shared_ptr<Kernel::Object> object) { | ||||||
|  |     auto lib_slot = GetAppletSlotFromPos(AppletPos::Library); | ||||||
|  |     auto lib_app_id = | ||||||
|  |         lib_slot != AppletSlot::Error ? GetAppletSlot(lib_slot)->applet_id : AppletId::None; | ||||||
|  |     if (from_applet_id == lib_app_id) { | ||||||
|  |         SendParameter({ | ||||||
|  |             .sender_id = from_applet_id, | ||||||
|  |             .destination_id = AppletId::Application, | ||||||
|  |             .signal = SignalType::DspSleep, | ||||||
|  |             .object = std::move(object), | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto sys_lib_slot = GetAppletSlotFromPos(AppletPos::SysLibrary); | ||||||
|  |     auto sys_lib_app_id = | ||||||
|  |         sys_lib_slot != AppletSlot::Error ? GetAppletSlot(sys_lib_slot)->applet_id : AppletId::None; | ||||||
|  |     if (from_applet_id == sys_lib_app_id) { | ||||||
|  |         auto sys_slot = GetAppletSlotFromPos(AppletPos::System); | ||||||
|  |         auto sys_app_id = | ||||||
|  |             sys_slot != AppletSlot::Error ? GetAppletSlot(sys_slot)->applet_id : AppletId::None; | ||||||
|  |         SendParameter({ | ||||||
|  |             .sender_id = from_applet_id, | ||||||
|  |             .destination_id = sys_app_id, | ||||||
|  |             .signal = SignalType::DspSleep, | ||||||
|  |             .object = std::move(object), | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode AppletManager::SendDspWakeUp(AppletId from_applet_id, | ||||||
|  |                                         std::shared_ptr<Kernel::Object> object) { | ||||||
|  |     auto lib_slot = GetAppletSlotFromPos(AppletPos::Library); | ||||||
|  |     auto lib_app_id = | ||||||
|  |         lib_slot != AppletSlot::Error ? GetAppletSlot(lib_slot)->applet_id : AppletId::None; | ||||||
|  |     if (from_applet_id == lib_app_id) { | ||||||
|  |         SendParameter({ | ||||||
|  |             .sender_id = from_applet_id, | ||||||
|  |             .destination_id = AppletId::Application, | ||||||
|  |             .signal = SignalType::DspSleep, | ||||||
|  |             .object = std::move(object), | ||||||
|  |         }); | ||||||
|  |     } else { | ||||||
|  |         auto sys_lib_slot = GetAppletSlotFromPos(AppletPos::SysLibrary); | ||||||
|  |         auto sys_lib_app_id = sys_lib_slot != AppletSlot::Error | ||||||
|  |                                   ? GetAppletSlot(sys_lib_slot)->applet_id | ||||||
|  |                                   : AppletId::None; | ||||||
|  |         if (from_applet_id == sys_lib_app_id) { | ||||||
|  |             auto sys_slot = GetAppletSlotFromPos(AppletPos::System); | ||||||
|  |             auto sys_app_id = | ||||||
|  |                 sys_slot != AppletSlot::Error ? GetAppletSlot(sys_slot)->applet_id : AppletId::None; | ||||||
|  |             SendParameter({ | ||||||
|  |                 .sender_id = from_applet_id, | ||||||
|  |                 .destination_id = sys_app_id, | ||||||
|  |                 .signal = SignalType::DspSleep, | ||||||
|  |                 .object = std::move(object), | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ResultCode AppletManager::PrepareToStartSystemApplet(AppletId applet_id) { | ResultCode AppletManager::PrepareToStartSystemApplet(AppletId applet_id) { | ||||||
|     // The real APT service returns an error if there's a pending APT parameter when this function
 |     // The real APT service returns an error if there's a pending APT parameter when this function
 | ||||||
|     // is called.
 |     // is called.
 | ||||||
|  | @ -963,10 +1082,7 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i | ||||||
|                           ErrorLevel::Status); |                           ErrorLevel::Status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO: Basic heuristic to guess media type, needs proper implementation.
 |     auto media_type = Service::AM::GetTitleMediaType(slot_data->title_id); | ||||||
|     auto media_type = ((slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000 |  | ||||||
|                           ? Service::FS::MediaType::SDMC |  | ||||||
|                           : Service::FS::MediaType::NAND; |  | ||||||
|     return AppletInfo{ |     return AppletInfo{ | ||||||
|         .title_id = slot_data->title_id, |         .title_id = slot_data->title_id, | ||||||
|         .media_type = media_type, |         .media_type = media_type, | ||||||
|  | @ -976,6 +1092,61 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultVal<Service::FS::MediaType> AppletManager::Unknown54(u32 in_param) { | ||||||
|  |     auto slot_data = GetAppletSlot(AppletSlot::Application); | ||||||
|  |     if (slot_data->applet_id == AppletId::None) { | ||||||
|  |         return ResultCode{ErrCodes::AppNotRunning, ErrorModule::Applet, ErrorSummary::InvalidState, | ||||||
|  |                           ErrorLevel::Permanent}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (in_param >= 0x80) { | ||||||
|  |         // TODO: Add error description name when the parameter is known.
 | ||||||
|  |         return ResultCode{10, ErrorModule::Applet, ErrorSummary::InvalidArgument, | ||||||
|  |                           ErrorLevel::Usage}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // TODO: Figure out what this logic is actually for.
 | ||||||
|  |     auto check_target = | ||||||
|  |         in_param >= 0x40 ? Service::FS::MediaType::GameCard : Service::FS::MediaType::SDMC; | ||||||
|  |     auto check_update = in_param == 0x01 || in_param == 0x42; | ||||||
|  | 
 | ||||||
|  |     auto app_media_type = Service::AM::GetTitleMediaType(slot_data->title_id); | ||||||
|  |     auto app_update_media_type = | ||||||
|  |         Service::AM::GetTitleMediaType(Service::AM::GetTitleUpdateId(slot_data->title_id)); | ||||||
|  |     if (app_media_type == check_target || (check_update && app_update_media_type == check_target)) { | ||||||
|  |         return Service::FS::MediaType::SDMC; | ||||||
|  |     } else { | ||||||
|  |         return Service::FS::MediaType::NAND; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TargetPlatform AppletManager::GetTargetPlatform() { | ||||||
|  |     if (Settings::values.is_new_3ds.GetValue() && !new_3ds_mode_blocked) { | ||||||
|  |         return TargetPlatform::New3ds; | ||||||
|  |     } else { | ||||||
|  |         return TargetPlatform::Old3ds; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ApplicationRunningMode AppletManager::GetApplicationRunningMode() { | ||||||
|  |     auto slot_data = GetAppletSlot(AppletSlot::Application); | ||||||
|  |     if (slot_data->applet_id == AppletId::None) { | ||||||
|  |         return ApplicationRunningMode::NoApplication; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // APT checks whether the system is a New 3DS and the 804MHz CPU speed is enabled to determine
 | ||||||
|  |     // the result.
 | ||||||
|  |     auto new_3ds_mode = GetTargetPlatform() == TargetPlatform::New3ds && | ||||||
|  |                         system.Kernel().GetNew3dsHwCapabilities().enable_804MHz_cpu; | ||||||
|  |     if (slot_data->registered) { | ||||||
|  |         return new_3ds_mode ? ApplicationRunningMode::New3dsRegistered | ||||||
|  |                             : ApplicationRunningMode::Old3dsRegistered; | ||||||
|  |     } else { | ||||||
|  |         return new_3ds_mode ? ApplicationRunningMode::New3dsUnregistered | ||||||
|  |                             : ApplicationRunningMode::Old3dsUnregistered; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type, | ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type, | ||||||
|                                                      ApplicationJumpFlags flags) { |                                                      ApplicationJumpFlags flags) { | ||||||
|     // A running application can not launch another application directly because the applet state
 |     // A running application can not launch another application directly because the applet state
 | ||||||
|  | @ -988,11 +1159,8 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType | ||||||
|     // Save the title data to send it to the Home Menu when DoApplicationJump is called.
 |     // Save the title data to send it to the Home Menu when DoApplicationJump is called.
 | ||||||
|     auto application_slot_data = GetAppletSlot(AppletSlot::Application); |     auto application_slot_data = GetAppletSlot(AppletSlot::Application); | ||||||
|     app_jump_parameters.current_title_id = application_slot_data->title_id; |     app_jump_parameters.current_title_id = application_slot_data->title_id; | ||||||
|     // TODO: Basic heuristic to guess media type, needs proper implementation.
 |  | ||||||
|     app_jump_parameters.current_media_type = |     app_jump_parameters.current_media_type = | ||||||
|         ((application_slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000 |         Service::AM::GetTitleMediaType(application_slot_data->title_id); | ||||||
|             ? Service::FS::MediaType::SDMC |  | ||||||
|             : Service::FS::MediaType::NAND; |  | ||||||
|     if (flags == ApplicationJumpFlags::UseCurrentParameters) { |     if (flags == ApplicationJumpFlags::UseCurrentParameters) { | ||||||
|         app_jump_parameters.next_title_id = app_jump_parameters.current_title_id; |         app_jump_parameters.next_title_id = app_jump_parameters.current_title_id; | ||||||
|         app_jump_parameters.next_media_type = app_jump_parameters.current_media_type; |         app_jump_parameters.next_media_type = app_jump_parameters.current_media_type; | ||||||
|  | @ -1055,19 +1223,8 @@ ResultCode AppletManager::DoApplicationJump(const DeliverArg& arg) { | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
|         */ |         */ | ||||||
| 
 | 
 | ||||||
|         auto new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type, |         NS::RebootToTitle(system, app_jump_parameters.next_media_type, | ||||||
|                                                          app_jump_parameters.next_title_id); |                           app_jump_parameters.next_title_id); | ||||||
|         if (new_path.empty() || !FileUtil::Exists(new_path)) { |  | ||||||
|             // TODO: This can happen if the requested title is not installed. Need a way to find
 |  | ||||||
|             // non-installed titles in the game list.
 |  | ||||||
|             LOG_CRITICAL( |  | ||||||
|                 Service_APT, |  | ||||||
|                 "Failed to find title during application jump: {} Resetting current title instead.", |  | ||||||
|                 new_path); |  | ||||||
|             new_path.clear(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         system.RequestReset(new_path); |  | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1126,13 +1283,14 @@ ResultCode AppletManager::StartApplication(const std::vector<u8>& parameter, | ||||||
|     app_start_parameters.reset(); |     app_start_parameters.reset(); | ||||||
| 
 | 
 | ||||||
|     if (!paused) { |     if (!paused) { | ||||||
|         return WakeupApplication(); |         return WakeupApplication(nullptr, {}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode AppletManager::WakeupApplication() { | ResultCode AppletManager::WakeupApplication(std::shared_ptr<Kernel::Object> object, | ||||||
|  |                                             const std::vector<u8>& buffer) { | ||||||
|     // Send a Wakeup signal via the apt parameter to the application once it registers itself.
 |     // Send a Wakeup signal via the apt parameter to the application once it registers itself.
 | ||||||
|     // The real APT service does this by spin waiting on another thread until the application is
 |     // The real APT service does this by spin waiting on another thread until the application is
 | ||||||
|     // registered.
 |     // registered.
 | ||||||
|  | @ -1140,6 +1298,8 @@ ResultCode AppletManager::WakeupApplication() { | ||||||
|         .sender_id = AppletId::HomeMenu, |         .sender_id = AppletId::HomeMenu, | ||||||
|         .destination_id = AppletId::Application, |         .destination_id = AppletId::Application, | ||||||
|         .signal = SignalType::Wakeup, |         .signal = SignalType::Wakeup, | ||||||
|  |         .object = std::move(object), | ||||||
|  |         .buffer = buffer, | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
|  | @ -1248,27 +1408,38 @@ void AppletManager::CaptureFrameBuffers() { | ||||||
| void AppletManager::LoadInputDevices() { | void AppletManager::LoadInputDevices() { | ||||||
|     home_button = Input::CreateDevice<Input::ButtonDevice>( |     home_button = Input::CreateDevice<Input::ButtonDevice>( | ||||||
|         Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]); |         Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]); | ||||||
|  |     power_button = Input::CreateDevice<Input::ButtonDevice>( | ||||||
|  |         Settings::values.current_input_profile.buttons[Settings::NativeButton::Power]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AppletManager::HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late) { | void AppletManager::ButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late) { | ||||||
|     if (is_device_reload_pending.exchange(false)) { |     if (is_device_reload_pending.exchange(false)) { | ||||||
|         LoadInputDevices(); |         LoadInputDevices(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const bool state = home_button->GetStatus(); |  | ||||||
|     // NOTE: We technically do support loading and jumping to home menu even if it isn't
 |     // NOTE: We technically do support loading and jumping to home menu even if it isn't
 | ||||||
|     // initially registered. However since the home menu suspend is not bug-free, we don't
 |     // initially registered. However since the home menu suspend is not bug-free, we don't
 | ||||||
|     // want normal users who didn't launch the home menu accidentally pressing the home
 |     // want normal users who didn't launch the home menu accidentally pressing the home
 | ||||||
|     // button binding and freezing their game, so for now, gate it to only environments
 |     // button binding and freezing their game, so for now, gate it to only environments
 | ||||||
|     // where the home menu was already loaded by the user (last condition).
 |     // where the home menu was already loaded by the user (last condition).
 | ||||||
|     if (state && !last_home_button_state && GetAppletSlot(AppletSlot::HomeMenu)->registered) { | 
 | ||||||
|         SendNotification(Notification::HomeButtonSingle); |     if (GetAppletSlot(AppletSlot::HomeMenu)->registered) { | ||||||
|  |         const bool home_state = home_button->GetStatus(); | ||||||
|  |         if (home_state && !last_home_button_state) { | ||||||
|  |             SendNotification(Notification::HomeButtonSingle); | ||||||
|  |         } | ||||||
|  |         last_home_button_state = home_state; | ||||||
|  | 
 | ||||||
|  |         const bool power_state = power_button->GetStatus(); | ||||||
|  |         if (power_state && !last_power_button_state) { | ||||||
|  |             SendNotificationToAll(Notification::PowerButtonClick); | ||||||
|  |         } | ||||||
|  |         last_power_button_state = power_state; | ||||||
|     } |     } | ||||||
|     last_home_button_state = state; |  | ||||||
| 
 | 
 | ||||||
|     // Reschedule recurrent event
 |     // Reschedule recurrent event
 | ||||||
|     Core::System::GetInstance().CoreTiming().ScheduleEvent( |     system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us) - cycles_late, | ||||||
|         usToCycles(home_button_update_interval_us) - cycles_late, home_button_update_event); |                                       button_update_event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AppletManager::AppletManager(Core::System& system) : system(system) { | AppletManager::AppletManager(Core::System& system) : system(system) { | ||||||
|  | @ -1286,12 +1457,11 @@ AppletManager::AppletManager(Core::System& system) : system(system) { | ||||||
|             system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "APT:Parameter"); |             system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "APT:Parameter"); | ||||||
|     } |     } | ||||||
|     HLE::Applets::Init(); |     HLE::Applets::Init(); | ||||||
|     home_button_update_event = Core::System::GetInstance().CoreTiming().RegisterEvent( |     button_update_event = system.CoreTiming().RegisterEvent( | ||||||
|         "Home Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) { |         "APT Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) { | ||||||
|             HomeButtonUpdateEvent(user_data, cycles_late); |             ButtonUpdateEvent(user_data, cycles_late); | ||||||
|         }); |         }); | ||||||
|     Core::System::GetInstance().CoreTiming().ScheduleEvent( |     system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us), button_update_event); | ||||||
|         usToCycles(home_button_update_interval_us), home_button_update_event); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AppletManager::~AppletManager() { | AppletManager::~AppletManager() { | ||||||
|  |  | ||||||
|  | @ -99,6 +99,21 @@ enum class AppletId : u32 { | ||||||
|     Memolib2 = 0x409, |     Memolib2 = 0x409, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /// Application Old/New 3DS target platforms
 | ||||||
|  | enum class TargetPlatform : u8 { | ||||||
|  |     Old3ds = 0, | ||||||
|  |     New3ds = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// Application Old/New 3DS running modes
 | ||||||
|  | enum class ApplicationRunningMode : u8 { | ||||||
|  |     NoApplication = 0, | ||||||
|  |     Old3dsRegistered = 1, | ||||||
|  |     New3dsRegistered = 2, | ||||||
|  |     Old3dsUnregistered = 3, | ||||||
|  |     New3dsUnregistered = 4, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /// Holds information about the parameters used in Send/Glance/ReceiveParameter
 | /// Holds information about the parameters used in Send/Glance/ReceiveParameter
 | ||||||
| struct MessageParameter { | struct MessageParameter { | ||||||
|     AppletId sender_id = AppletId::None; |     AppletId sender_id = AppletId::None; | ||||||
|  | @ -256,10 +271,14 @@ public: | ||||||
|     ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes); |     ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes); | ||||||
| 
 | 
 | ||||||
|     ResultCode Enable(AppletAttributes attributes); |     ResultCode Enable(AppletAttributes attributes); | ||||||
|  |     ResultCode Finalize(AppletId app_id); | ||||||
|  |     u32 CountRegisteredApplet(); | ||||||
|     bool IsRegistered(AppletId app_id); |     bool IsRegistered(AppletId app_id); | ||||||
|  |     ResultVal<AppletAttributes> GetAttribute(AppletId app_id); | ||||||
| 
 | 
 | ||||||
|     ResultVal<Notification> InquireNotification(AppletId app_id); |     ResultVal<Notification> InquireNotification(AppletId app_id); | ||||||
|     ResultCode SendNotification(Notification notification); |     ResultCode SendNotification(Notification notification); | ||||||
|  |     void SendNotificationToAll(Notification notification); | ||||||
| 
 | 
 | ||||||
|     ResultCode PrepareToStartLibraryApplet(AppletId applet_id); |     ResultCode PrepareToStartLibraryApplet(AppletId applet_id); | ||||||
|     ResultCode PreloadLibraryApplet(AppletId applet_id); |     ResultCode PreloadLibraryApplet(AppletId applet_id); | ||||||
|  | @ -271,6 +290,9 @@ public: | ||||||
|                                   const std::vector<u8>& buffer); |                                   const std::vector<u8>& buffer); | ||||||
|     ResultCode CancelLibraryApplet(bool app_exiting); |     ResultCode CancelLibraryApplet(bool app_exiting); | ||||||
| 
 | 
 | ||||||
|  |     ResultCode SendDspSleep(AppletId from_applet_id, std::shared_ptr<Kernel::Object> object); | ||||||
|  |     ResultCode SendDspWakeUp(AppletId from_applet_id, std::shared_ptr<Kernel::Object> object); | ||||||
|  | 
 | ||||||
|     ResultCode PrepareToStartSystemApplet(AppletId applet_id); |     ResultCode PrepareToStartSystemApplet(AppletId applet_id); | ||||||
|     ResultCode StartSystemApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object, |     ResultCode StartSystemApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object, | ||||||
|                                  const std::vector<u8>& buffer); |                                  const std::vector<u8>& buffer); | ||||||
|  | @ -294,8 +316,10 @@ public: | ||||||
|                                           ApplicationJumpFlags flags); |                                           ApplicationJumpFlags flags); | ||||||
|     ResultCode DoApplicationJump(const DeliverArg& arg); |     ResultCode DoApplicationJump(const DeliverArg& arg); | ||||||
| 
 | 
 | ||||||
|     boost::optional<DeliverArg> ReceiveDeliverArg() const { |     boost::optional<DeliverArg> ReceiveDeliverArg() { | ||||||
|         return deliver_arg; |         auto arg = deliver_arg; | ||||||
|  |         deliver_arg = boost::none; | ||||||
|  |         return arg; | ||||||
|     } |     } | ||||||
|     void SetDeliverArg(boost::optional<DeliverArg> arg) { |     void SetDeliverArg(boost::optional<DeliverArg> arg) { | ||||||
|         deliver_arg = std::move(arg); |         deliver_arg = std::move(arg); | ||||||
|  | @ -324,7 +348,8 @@ public: | ||||||
|     ResultCode PrepareToStartApplication(u64 title_id, FS::MediaType media_type); |     ResultCode PrepareToStartApplication(u64 title_id, FS::MediaType media_type); | ||||||
|     ResultCode StartApplication(const std::vector<u8>& parameter, const std::vector<u8>& hmac, |     ResultCode StartApplication(const std::vector<u8>& parameter, const std::vector<u8>& hmac, | ||||||
|                                 bool paused); |                                 bool paused); | ||||||
|     ResultCode WakeupApplication(); |     ResultCode WakeupApplication(std::shared_ptr<Kernel::Object> object, | ||||||
|  |                                  const std::vector<u8>& buffer); | ||||||
|     ResultCode CancelApplication(); |     ResultCode CancelApplication(); | ||||||
| 
 | 
 | ||||||
|     struct AppletManInfo { |     struct AppletManInfo { | ||||||
|  | @ -349,6 +374,10 @@ public: | ||||||
|         return app_jump_parameters; |         return app_jump_parameters; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     ResultVal<Service::FS::MediaType> Unknown54(u32 in_param); | ||||||
|  |     TargetPlatform GetTargetPlatform(); | ||||||
|  |     ApplicationRunningMode GetApplicationRunningMode(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     /// APT lock retrieved via GetLockHandle.
 |     /// APT lock retrieved via GetLockHandle.
 | ||||||
|     std::shared_ptr<Kernel::Mutex> lock; |     std::shared_ptr<Kernel::Mutex> lock; | ||||||
|  | @ -427,10 +456,16 @@ private: | ||||||
|     bool application_cancelled = false; |     bool application_cancelled = false; | ||||||
|     AppletSlot application_close_target = AppletSlot::Error; |     AppletSlot application_close_target = AppletSlot::Error; | ||||||
| 
 | 
 | ||||||
|     Core::TimingEventType* home_button_update_event; |     // This flag is used to determine if an app that supports New 3DS capabilities should use them.
 | ||||||
|  |     // It also affects the results of APT:GetTargetPlatform and APT:GetApplicationRunningMode.
 | ||||||
|  |     bool new_3ds_mode_blocked = false; | ||||||
|  | 
 | ||||||
|  |     Core::TimingEventType* button_update_event; | ||||||
|     std::atomic<bool> is_device_reload_pending{true}; |     std::atomic<bool> is_device_reload_pending{true}; | ||||||
|     std::unique_ptr<Input::ButtonDevice> home_button; |     std::unique_ptr<Input::ButtonDevice> home_button; | ||||||
|  |     std::unique_ptr<Input::ButtonDevice> power_button; | ||||||
|     bool last_home_button_state = false; |     bool last_home_button_state = false; | ||||||
|  |     bool last_power_button_state = false; | ||||||
| 
 | 
 | ||||||
|     Core::System& system; |     Core::System& system; | ||||||
| 
 | 
 | ||||||
|  | @ -455,7 +490,7 @@ private: | ||||||
|     void CaptureFrameBuffers(); |     void CaptureFrameBuffers(); | ||||||
| 
 | 
 | ||||||
|     void LoadInputDevices(); |     void LoadInputDevices(); | ||||||
|     void HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late); |     void ButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late); | ||||||
| 
 | 
 | ||||||
|     template <class Archive> |     template <class Archive> | ||||||
|     void serialize(Archive& ar, const unsigned int file_version) { |     void serialize(Archive& ar, const unsigned int file_version) { | ||||||
|  | @ -474,6 +509,7 @@ private: | ||||||
|             ar& ordered_to_close_application; |             ar& ordered_to_close_application; | ||||||
|             ar& application_cancelled; |             ar& application_cancelled; | ||||||
|             ar& application_close_target; |             ar& application_close_target; | ||||||
|  |             ar& new_3ds_mode_blocked; | ||||||
|             ar& lock; |             ar& lock; | ||||||
|             ar& capture_info; |             ar& capture_info; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -16,16 +16,19 @@ | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.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/am/am.h" | ||||||
| #include "core/hle/service/apt/applet_manager.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" | ||||||
| #include "core/hle/service/apt/apt_u.h" | #include "core/hle/service/apt/apt_u.h" | ||||||
| #include "core/hle/service/apt/bcfnt/bcfnt.h" | #include "core/hle/service/apt/bcfnt/bcfnt.h" | ||||||
|  | #include "core/hle/service/apt/ns.h" | ||||||
| #include "core/hle/service/apt/ns_c.h" | #include "core/hle/service/apt/ns_c.h" | ||||||
| #include "core/hle/service/apt/ns_s.h" | #include "core/hle/service/apt/ns_s.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/fs/fs_user.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" | ||||||
|  | @ -41,7 +44,6 @@ void Module::serialize(Archive& ar, const unsigned int file_version) { | ||||||
|     ar& shared_font_loaded; |     ar& shared_font_loaded; | ||||||
|     ar& shared_font_relocated; |     ar& shared_font_relocated; | ||||||
|     ar& cpu_percent; |     ar& cpu_percent; | ||||||
|     ar& unknown_ns_state_field; |  | ||||||
|     ar& screen_capture_post_permission; |     ar& screen_capture_post_permission; | ||||||
|     ar& applet_manager; |     ar& applet_manager; | ||||||
|     if (file_version > 0) { |     if (file_version > 0) { | ||||||
|  | @ -90,14 +92,19 @@ void Module::NSInterface::RebootSystem(Kernel::HLERequestContext& ctx) { | ||||||
|     const auto title_id = rp.Pop<u64>(); |     const auto title_id = rp.Pop<u64>(); | ||||||
|     const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>()); |     const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>()); | ||||||
|     rp.Skip(1, false); // Skip padding
 |     rp.Skip(1, false); // Skip padding
 | ||||||
|  |     // TODO: Utilize requested memory type.
 | ||||||
|     const auto mem_type = rp.Pop<u8>(); |     const auto mem_type = rp.Pop<u8>(); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, |     LOG_WARNING(Service_APT, | ||||||
|                 "called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}", |                 "called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}", | ||||||
|                 launch_title, title_id, media_type, mem_type); |                 launch_title, title_id, media_type, mem_type); | ||||||
| 
 | 
 | ||||||
|     // TODO: Implement loading a specific title.
 |     // TODO: Handle mem type.
 | ||||||
|     apt->system.RequestReset(); |     if (launch_title) { | ||||||
|  |         NS::RebootToTitle(apt->system, media_type, title_id); | ||||||
|  |     } else { | ||||||
|  |         apt->system.RequestReset(); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|  | @ -371,6 +378,16 @@ void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) { | ||||||
|     rb.Push(apt->applet_manager->Enable(attributes)); |     rb.Push(apt->applet_manager->Enable(attributes)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Module::APTInterface::Finalize(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto applet_id = rp.PopEnum<AppletId>(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called applet_id={:08X}", applet_id); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(apt->applet_manager->Finalize(applet_id)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|     auto applet_pos = rp.PopEnum<AppletPos>(); |     auto applet_pos = rp.PopEnum<AppletPos>(); | ||||||
|  | @ -391,6 +408,16 @@ void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Module::APTInterface::CountRegisteredApplet(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called"); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     rb.Push(apt->applet_manager->CountRegisteredApplet()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|     const auto app_id = rp.PopEnum<AppletId>(); |     const auto app_id = rp.PopEnum<AppletId>(); | ||||||
|  | @ -402,6 +429,23 @@ void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id); |     LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Module::APTInterface::GetAttribute(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto app_id = rp.PopEnum<AppletId>(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id); | ||||||
|  | 
 | ||||||
|  |     auto applet_attr = apt->applet_manager->GetAttribute(app_id); | ||||||
|  |     if (applet_attr.Failed()) { | ||||||
|  |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |         rb.Push(applet_attr.Code()); | ||||||
|  |     } else { | ||||||
|  |         IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|  |         rb.Push(RESULT_SUCCESS); | ||||||
|  |         rb.Push(applet_attr.Unwrap().raw); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|     const auto app_id = rp.PopEnum<AppletId>(); |     const auto app_id = rp.PopEnum<AppletId>(); | ||||||
|  | @ -557,6 +601,21 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte | ||||||
|     rb.Push(static_cast<u8>(parameters.next_media_type)); |     rb.Push(static_cast<u8>(parameters.next_media_type)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Module::APTInterface::SendDeliverArg(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto param_size = rp.Pop<u32>(); | ||||||
|  |     const auto hmac_size = rp.Pop<u32>(); | ||||||
|  |     const auto param = rp.PopStaticBuffer(); | ||||||
|  |     const auto hmac = rp.PopStaticBuffer(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size); | ||||||
|  | 
 | ||||||
|  |     apt->applet_manager->SetDeliverArg(DeliverArg{param, hmac}); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|     const auto param_size = rp.Pop<u32>(); |     const auto param_size = rp.Pop<u32>(); | ||||||
|  | @ -611,7 +670,7 @@ void Module::APTInterface::WakeupApplication(Kernel::HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_APT, "called"); |     LOG_DEBUG(Service_APT, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     rb.Push(apt->applet_manager->WakeupApplication()); |     rb.Push(apt->applet_manager->WakeupApplication(nullptr, {})); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::APTInterface::CancelApplication(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::CancelApplication(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -856,6 +915,28 @@ void Module::APTInterface::OrderToCloseSystemApplet(Kernel::HLERequestContext& c | ||||||
|     rb.Push(apt->applet_manager->OrderToCloseSystemApplet()); |     rb.Push(apt->applet_manager->OrderToCloseSystemApplet()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Module::APTInterface::SendDspSleep(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto from_app_id = rp.PopEnum<AppletId>(); | ||||||
|  |     const auto object = rp.PopGenericObject(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called, from_app_id={:08X}", from_app_id); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(apt->applet_manager->SendDspSleep(from_app_id, object)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Module::APTInterface::SendDspWakeUp(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto from_app_id = rp.PopEnum<AppletId>(); | ||||||
|  |     const auto object = rp.PopGenericObject(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called, from_app_id={:08X}", from_app_id); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(apt->applet_manager->SendDspWakeUp(from_app_id, object)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Module::APTInterface::PrepareToJumpToHomeMenu(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::PrepareToJumpToHomeMenu(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
| 
 | 
 | ||||||
|  | @ -972,29 +1053,124 @@ void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) { | ||||||
|     rb.PushStaticBuffer(std::move(screen_capture_buffer), 0); |     rb.PushStaticBuffer(std::move(screen_capture_buffer), 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::APTInterface::SetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::Unknown54(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|  |     auto in_param = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "called, screen_capture_post_permission={}", |     LOG_DEBUG(Service_APT, "called, in_param={}", in_param); | ||||||
|               apt->screen_capture_post_permission); |  | ||||||
| 
 | 
 | ||||||
|     apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF); |     auto media_type = apt->applet_manager->Unknown54(in_param); | ||||||
|  |     if (media_type.Failed()) { | ||||||
|  |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |         rb.Push(media_type.Code()); | ||||||
|  |     } else { | ||||||
|  |         IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|  |         rb.Push(RESULT_SUCCESS); | ||||||
|  |         rb.PushEnum(media_type.Unwrap()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Module::APTInterface::SetScreenCapturePostPermission(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     auto permission = rp.Pop<u32>(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called, permission={}", permission); | ||||||
|  | 
 | ||||||
|  |     apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(permission & 0xF); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     rb.Push(RESULT_SUCCESS); // No error
 |     rb.Push(RESULT_SUCCESS); // No error
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::APTInterface::GetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::GetScreenCapturePostPermission(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_APT, "(STUBBED) called, screen_capture_post_permission={}", |     LOG_DEBUG(Service_APT, "called"); | ||||||
|               apt->screen_capture_post_permission); |  | ||||||
| 
 | 
 | ||||||
|     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(static_cast<u32>(apt->screen_capture_post_permission)); |     rb.Push(static_cast<u32>(apt->screen_capture_post_permission)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Module::APTInterface::WakeupApplication2(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto buffer_size = rp.Pop<u32>(); | ||||||
|  |     const auto object = rp.PopGenericObject(); | ||||||
|  |     const auto buffer = rp.PopStaticBuffer(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called buffer_size={:#010X}", buffer_size); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(apt->applet_manager->WakeupApplication(object, buffer)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Module::APTInterface::GetProgramId(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto process_id = rp.PopPID(); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called process_id={}", process_id); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  | 
 | ||||||
|  |     auto fs_user = | ||||||
|  |         Core::System::GetInstance().ServiceManager().GetService<Service::FS::FS_USER>("fs:USER"); | ||||||
|  |     ASSERT_MSG(fs_user != nullptr, "fs:USER service is missing."); | ||||||
|  | 
 | ||||||
|  |     auto program_info_result = fs_user->GetProgramLaunchInfo(process_id); | ||||||
|  |     if (program_info_result.Failed()) { | ||||||
|  |         // On failure, APT still returns a success result with a program ID of 0.
 | ||||||
|  |         rb.Push<u64>(0); | ||||||
|  |     } else { | ||||||
|  |         rb.Push(program_info_result.Unwrap().program_id); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Module::APTInterface::GetProgramInfo(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto title_id = rp.Pop<u64>(); | ||||||
|  |     const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>()); | ||||||
|  |     rp.Skip(1, false); // Skip padding
 | ||||||
|  | 
 | ||||||
|  |     LOG_WARNING(Service_APT, "called title_id={:016X}, media_type={:02X}", title_id, media_type); | ||||||
|  | 
 | ||||||
|  |     std::string path = Service::AM::GetTitleContentPath(media_type, title_id); | ||||||
|  |     auto loader = Loader::GetLoader(path); | ||||||
|  |     if (!loader) { | ||||||
|  |         LOG_WARNING(Service_APT, "Could not find .app for title 0x{:016x}", title_id); | ||||||
|  | 
 | ||||||
|  |         // TODO: Proper error code
 | ||||||
|  |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |         rb.Push(RESULT_UNKNOWN); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto memory_mode = loader->LoadKernelMemoryMode(); | ||||||
|  |     if (memory_mode.second != Loader::ResultStatus::Success || !memory_mode.first) { | ||||||
|  |         LOG_ERROR(Service_APT, "Could not load memory mode for title 0x{:016x}", title_id); | ||||||
|  | 
 | ||||||
|  |         // TODO: Proper error code
 | ||||||
|  |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |         rb.Push(RESULT_UNKNOWN); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto core_version = loader->LoadCoreVersion(); | ||||||
|  |     if (core_version.second != Loader::ResultStatus::Success || !core_version.first) { | ||||||
|  |         LOG_ERROR(Service_APT, "Could not load core version for title 0x{:016x}", title_id); | ||||||
|  | 
 | ||||||
|  |         // TODO: Proper error code
 | ||||||
|  |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |         rb.Push(RESULT_UNKNOWN); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     rb.Push(static_cast<u8>(memory_mode.first.value())); | ||||||
|  |     rb.Push(core_version.first.value()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|     const auto app_id = rp.PopEnum<AppletId>(); |     const auto app_id = rp.PopEnum<AppletId>(); | ||||||
|  | @ -1154,37 +1330,83 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) { | ||||||
|     rb.PushMappedBuffer(output); |     rb.PushMappedBuffer(output); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::Reboot(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  |     const auto title_id = rp.Pop<u64>(); | ||||||
|  |     const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>()); | ||||||
|  |     rp.Skip(1, false); // Skip padding
 | ||||||
|  |     const auto mem_type = rp.Pop<u8>(); | ||||||
|  |     const auto firm_tid_low = rp.Pop<u32>(); | ||||||
|  | 
 | ||||||
|  |     LOG_WARNING(Service_APT, | ||||||
|  |                 "called title_id={:016X}, media_type={:02X}, mem_type={:02X}, firm_tid_low={:08X}", | ||||||
|  |                 title_id, media_type, mem_type, firm_tid_low); | ||||||
|  | 
 | ||||||
|  |     // TODO: Handle mem type and FIRM TID low.
 | ||||||
|  |     NS::RebootToTitle(apt->system, media_type, title_id); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Module::APTInterface::HardwareResetAsync(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called"); |     LOG_WARNING(Service_APT, "called"); | ||||||
|  | 
 | ||||||
|  |     apt->system.RequestReset(); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Module::APTInterface::GetTargetPlatform(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called"); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|     if (apt->unknown_ns_state_field) { |     rb.Push(RESULT_SUCCESS); | ||||||
|         rb.Push(RESULT_SUCCESS); |     rb.PushEnum(apt->applet_manager->GetTargetPlatform()); | ||||||
|         rb.Push<u32>(0); |  | ||||||
|     } else { |  | ||||||
|         PTM::CheckNew3DS(rb); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called"); | ||||||
|  | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
| 
 |  | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called"); |  | ||||||
| 
 |  | ||||||
|     PTM::CheckNew3DS(rb); |     PTM::CheckNew3DS(rb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::GetApplicationRunningMode(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called"); | ||||||
|  | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
| 
 |  | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called"); |  | ||||||
| 
 |  | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.Push<u8>(Settings::values.is_new_3ds ? 2 : 1); |     rb.PushEnum(apt->applet_manager->GetApplicationRunningMode()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Module::APTInterface::IsStandardMemoryLayout(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called"); | ||||||
|  | 
 | ||||||
|  |     bool is_standard; | ||||||
|  |     if (Settings::values.is_new_3ds) { | ||||||
|  |         // Memory layout is standard if it is not NewDev1 (178MB)
 | ||||||
|  |         is_standard = apt->system.Kernel().GetNew3dsHwCapabilities().memory_mode != | ||||||
|  |                       Kernel::New3dsMemoryMode::NewDev1; | ||||||
|  |     } else { | ||||||
|  |         // Memory layout is standard if it is Prod (64MB)
 | ||||||
|  |         is_standard = apt->system.Kernel().GetMemoryMode() == Kernel::MemoryMode::Prod; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     rb.Push(is_standard); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) { | void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -214,6 +214,15 @@ public: | ||||||
|          */ |          */ | ||||||
|         void Enable(Kernel::HLERequestContext& ctx); |         void Enable(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::Finalize service function | ||||||
|  |          *  Inputs: | ||||||
|  |          *      1 : Applet ID | ||||||
|  |          *  Outputs: | ||||||
|  |          *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          */ | ||||||
|  |         void Finalize(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::GetAppletManInfo service function. |          * APT::GetAppletManInfo service function. | ||||||
|          *  Inputs: |          *  Inputs: | ||||||
|  | @ -241,6 +250,15 @@ public: | ||||||
|          */ |          */ | ||||||
|         void GetAppletInfo(Kernel::HLERequestContext& ctx); |         void GetAppletInfo(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::CountRegisteredApplet service function | ||||||
|  |          *  Outputs: | ||||||
|  |          *      0 : Return header | ||||||
|  |          *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          *      2 : Number of registered applets | ||||||
|  |          */ | ||||||
|  |         void CountRegisteredApplet(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::IsRegistered service function. This returns whether the specified AppID is |          * APT::IsRegistered service function. This returns whether the specified AppID is | ||||||
|          * registered with NS yet. An AppID is "registered" once the process associated with the |          * registered with NS yet. An AppID is "registered" once the process associated with the | ||||||
|  | @ -257,6 +275,17 @@ public: | ||||||
|          */ |          */ | ||||||
|         void IsRegistered(Kernel::HLERequestContext& ctx); |         void IsRegistered(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::GetAttribute service function | ||||||
|  |          *  Inputs: | ||||||
|  |          *      1 : AppID | ||||||
|  |          *  Outputs: | ||||||
|  |          *      0 : Return header | ||||||
|  |          *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          *      2 : Applet Attributes | ||||||
|  |          */ | ||||||
|  |         void GetAttribute(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|         void InquireNotification(Kernel::HLERequestContext& ctx); |         void InquireNotification(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|  | @ -596,6 +625,21 @@ public: | ||||||
|          */ |          */ | ||||||
|         void GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx); |         void GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::SendDeliverArg service function | ||||||
|  |          *  Inputs: | ||||||
|  |          *      0 : Command header [0x00340084] | ||||||
|  |          *      1 : Parameter Size (capped to 0x300) | ||||||
|  |          *      2 : HMAC Size (capped to 0x20) | ||||||
|  |          *      3 : (Parameter Size << 14) | 2 | ||||||
|  |          *      4 : Input buffer for Parameter | ||||||
|  |          *      5 : (HMAC Size << 14) | 0x802 | ||||||
|  |          *      6 : Input buffer for HMAC | ||||||
|  |          *  Outputs: | ||||||
|  |          *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          */ | ||||||
|  |         void SendDeliverArg(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::ReceiveDeliverArg service function |          * APT::ReceiveDeliverArg service function | ||||||
|          *  Inputs: |          *  Inputs: | ||||||
|  | @ -687,6 +731,30 @@ public: | ||||||
|          */ |          */ | ||||||
|         void OrderToCloseSystemApplet(Kernel::HLERequestContext& ctx); |         void OrderToCloseSystemApplet(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::SendDspSleep service function | ||||||
|  |          *  Inputs: | ||||||
|  |          *      1 : Source App ID | ||||||
|  |          *      2 : Handle translation header (0x0) | ||||||
|  |          *      3 : Handle parameter | ||||||
|  |          *  Outputs: | ||||||
|  |          *      0 : Header code | ||||||
|  |          *      1 : Result code | ||||||
|  |          */ | ||||||
|  |         void SendDspSleep(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::SendDspWakeUp service function | ||||||
|  |          *  Inputs: | ||||||
|  |          *      1 : Source App ID | ||||||
|  |          *      2 : Handle translation header (0x0) | ||||||
|  |          *      3 : Handle parameter | ||||||
|  |          *  Outputs: | ||||||
|  |          *      0 : Header code | ||||||
|  |          *      1 : Result code | ||||||
|  |          */ | ||||||
|  |         void SendDspWakeUp(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::PrepareToJumpToHomeMenu service function |          * APT::PrepareToJumpToHomeMenu service function | ||||||
|          *  Inputs: |          *  Inputs: | ||||||
|  | @ -818,27 +886,97 @@ public: | ||||||
|         void GetStartupArgument(Kernel::HLERequestContext& ctx); |         void GetStartupArgument(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::SetScreenCapPostPermission service function |          * APT::Unknown54 service function | ||||||
|  |          *  Inputs: | ||||||
|  |          *      0 : Header Code[0x00540040] | ||||||
|  |          *      1 : Unknown | ||||||
|  |          *  Outputs: | ||||||
|  |          *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          *      2 : Media Type | ||||||
|  |          */ | ||||||
|  |         void Unknown54(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::SetScreenCapturePostPermission service function | ||||||
|          *  Inputs: |          *  Inputs: | ||||||
|          *      0 : Header Code[0x00550040] |          *      0 : Header Code[0x00550040] | ||||||
|          *      1 : u8 The screenshot posting permission |          *      1 : u8 The screenshot posting permission | ||||||
|          *  Outputs: |          *  Outputs: | ||||||
|          *      1 : Result of function, 0 on success, otherwise error code |          *      1 : Result of function, 0 on success, otherwise error code | ||||||
|          */ |          */ | ||||||
|         void SetScreenCapPostPermission(Kernel::HLERequestContext& ctx); |         void SetScreenCapturePostPermission(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::GetScreenCapPostPermission service function |          * APT::GetScreenCapturePostPermission service function | ||||||
|          *  Inputs: |          *  Inputs: | ||||||
|          *      0 : Header Code[0x00560000] |          *      0 : Header Code[0x00560000] | ||||||
|          *  Outputs: |          *  Outputs: | ||||||
|          *      1 : Result of function, 0 on success, otherwise error code |          *      1 : Result of function, 0 on success, otherwise error code | ||||||
|          *      2 : u8 The screenshot posting permission |          *      2 : u8 The screenshot posting permission | ||||||
|          */ |          */ | ||||||
|         void GetScreenCapPostPermission(Kernel::HLERequestContext& ctx); |         void GetScreenCapturePostPermission(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::CheckNew3DSApp service function |          * APT::WakeupApplication2 service function. | ||||||
|  |          *  Inputs: | ||||||
|  |          *     1 : Buffer parameter size, (max is 0x1000) | ||||||
|  |          *     2 : Handle translation header (0x0) | ||||||
|  |          *     3 : Handle parameter | ||||||
|  |          *     4 : (Buffer parameter size << 14) | 2 | ||||||
|  |          *     5 : Buffer parameter pointer | ||||||
|  |          * Outputs: | ||||||
|  |          *     0 : Return Header | ||||||
|  |          *     1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          */ | ||||||
|  |         void WakeupApplication2(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::GetProgramId service function. | ||||||
|  |          *  Inputs: | ||||||
|  |          *     1 : Process ID translation header (0x20) | ||||||
|  |          *     2 : Process ID (filled in by kernel) | ||||||
|  |          * Outputs: | ||||||
|  |          *     0 : Return Header | ||||||
|  |          *     1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          *     2-3 : u64 Program ID | ||||||
|  |          */ | ||||||
|  |         void GetProgramId(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::GetProgramInfo service function. | ||||||
|  |          * Inputs: | ||||||
|  |          *     1-2 : Title ID | ||||||
|  |          *     3 : Media Type | ||||||
|  |          *     4 : Padding | ||||||
|  |          * Outputs: | ||||||
|  |          *     1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          *     2 : Required app memory mode | ||||||
|  |          *     3 : Required app FIRM title ID low | ||||||
|  |          */ | ||||||
|  |         void GetProgramInfo(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::Reboot service function. | ||||||
|  |          * Inputs: | ||||||
|  |          *     1-2 : Title ID | ||||||
|  |          *     3 : Media Type | ||||||
|  |          *     4 : Padding | ||||||
|  |          *     5 : Launch memory type | ||||||
|  |          *     6 : FIRM title ID low 32-bits | ||||||
|  |          * Outputs: | ||||||
|  |          *     1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          */ | ||||||
|  |         void Reboot(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::HardwareResetAsync service function. | ||||||
|  |          * Outputs: | ||||||
|  |          *     1 : Result of function, 0 on success, otherwise error code | ||||||
|  |          */ | ||||||
|  |         void HardwareResetAsync(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::GetTargetPlatform service function | ||||||
|          *  Outputs: |          *  Outputs: | ||||||
|          *      1: Result code, 0 on success, otherwise error code |          *      1: Result code, 0 on success, otherwise error code | ||||||
|          *      2: u8 output: 0 = Old3DS, 1 = New3DS. |          *      2: u8 output: 0 = Old3DS, 1 = New3DS. | ||||||
|  | @ -849,7 +987,7 @@ public: | ||||||
|          *  Normally this NS state field is zero, however this state field is set to 1 |          *  Normally this NS state field is zero, however this state field is set to 1 | ||||||
|          *  when APT:PrepareToStartApplication is used with flags bit8 is set. |          *  when APT:PrepareToStartApplication is used with flags bit8 is set. | ||||||
|          */ |          */ | ||||||
|         void CheckNew3DSApp(Kernel::HLERequestContext& ctx); |         void GetTargetPlatform(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * Wrapper for PTMSYSM:CheckNew3DS |          * Wrapper for PTMSYSM:CheckNew3DS | ||||||
|  | @ -861,12 +999,20 @@ public: | ||||||
|         void CheckNew3DS(Kernel::HLERequestContext& ctx); |         void CheckNew3DS(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::Unknown0x0103 service function. Determines whether Smash 4 allows C-Stick |          * APT::GetApplicationRunningMode service function | ||||||
|          *  Outputs: |          *  Outputs: | ||||||
|          *      1: Result code, 0 on success otherwise error code |          *      1: Result code, 0 on success otherwise error code | ||||||
|          *      2: u8 output: 2 = New3DS+valid/initialized (in Smash 4), 1 = Old3DS or invalid |          *      2: u8 output: 0 = No application, 1/3 = Old 3DS, 2/4 = New 3DS | ||||||
|          */ |          */ | ||||||
|         void Unknown0x0103(Kernel::HLERequestContext& ctx); |         void GetApplicationRunningMode(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * APT::IsStandardMemoryLayout service function | ||||||
|  |          *  Outputs: | ||||||
|  |          *      1: Result code, 0 on success otherwise error code | ||||||
|  |          *      2: bool output: Whether the system is in its standard memory layout. | ||||||
|  |          */ | ||||||
|  |         void IsStandardMemoryLayout(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * APT::IsTitleAllowed service function |          * APT::IsTitleAllowed service function | ||||||
|  | @ -906,9 +1052,6 @@ private: | ||||||
| 
 | 
 | ||||||
|     u32 cpu_percent = 0; ///< CPU time available to the running application
 |     u32 cpu_percent = 0; ///< CPU time available to the running application
 | ||||||
| 
 | 
 | ||||||
|     // APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode
 |  | ||||||
|     u8 unknown_ns_state_field = 0; |  | ||||||
| 
 |  | ||||||
|     std::array<u8, SysMenuArgSize> sys_menu_arg_buffer; |     std::array<u8, SysMenuArgSize> sys_menu_arg_buffer; | ||||||
| 
 | 
 | ||||||
|     ScreencapPostPermission screen_capture_post_permission = |     ScreencapPostPermission screen_capture_post_permission = | ||||||
|  |  | ||||||
|  | @ -14,13 +14,13 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | ||||||
|         {0x0001, &APT_A::GetLockHandle, "GetLockHandle"}, |         {0x0001, &APT_A::GetLockHandle, "GetLockHandle"}, | ||||||
|         {0x0002, &APT_A::Initialize, "Initialize"}, |         {0x0002, &APT_A::Initialize, "Initialize"}, | ||||||
|         {0x0003, &APT_A::Enable, "Enable"}, |         {0x0003, &APT_A::Enable, "Enable"}, | ||||||
|         {0x0004, nullptr, "Finalize"}, |         {0x0004, &APT_A::Finalize, "Finalize"}, | ||||||
|         {0x0005, &APT_A::GetAppletManInfo, "GetAppletManInfo"}, |         {0x0005, &APT_A::GetAppletManInfo, "GetAppletManInfo"}, | ||||||
|         {0x0006, &APT_A::GetAppletInfo, "GetAppletInfo"}, |         {0x0006, &APT_A::GetAppletInfo, "GetAppletInfo"}, | ||||||
|         {0x0007, nullptr, "GetLastSignaledAppletId"}, |         {0x0007, nullptr, "GetLastSignaledAppletId"}, | ||||||
|         {0x0008, nullptr, "CountRegisteredApplet"}, |         {0x0008, &APT_A::CountRegisteredApplet, "CountRegisteredApplet"}, | ||||||
|         {0x0009, &APT_A::IsRegistered, "IsRegistered"}, |         {0x0009, &APT_A::IsRegistered, "IsRegistered"}, | ||||||
|         {0x000A, nullptr, "GetAttribute"}, |         {0x000A, &APT_A::GetAttribute, "GetAttribute"}, | ||||||
|         {0x000B, &APT_A::InquireNotification, "InquireNotification"}, |         {0x000B, &APT_A::InquireNotification, "InquireNotification"}, | ||||||
|         {0x000C, &APT_A::SendParameter, "SendParameter"}, |         {0x000C, &APT_A::SendParameter, "SendParameter"}, | ||||||
|         {0x000D, &APT_A::ReceiveParameter, "ReceiveParameter"}, |         {0x000D, &APT_A::ReceiveParameter, "ReceiveParameter"}, | ||||||
|  | @ -39,7 +39,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | ||||||
|         {0x001A, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, |         {0x001A, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, | ||||||
|         {0x001B, &APT_A::StartApplication, "StartApplication"}, |         {0x001B, &APT_A::StartApplication, "StartApplication"}, | ||||||
|         {0x001C, &APT_A::WakeupApplication, "WakeupApplication"}, |         {0x001C, &APT_A::WakeupApplication, "WakeupApplication"}, | ||||||
|         {0x001D, nullptr, "CancelApplication"}, |         {0x001D, &APT_A::CancelApplication, "CancelApplication"}, | ||||||
|         {0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"}, |         {0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"}, | ||||||
|         {0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"}, |         {0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"}, | ||||||
|         {0x0020, nullptr, "StartNewestHomeMenu"}, |         {0x0020, nullptr, "StartNewestHomeMenu"}, | ||||||
|  | @ -62,7 +62,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | ||||||
|         {0x0031, &APT_A::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, |         {0x0031, &APT_A::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, | ||||||
|         {0x0032, &APT_A::DoApplicationJump, "DoApplicationJump"}, |         {0x0032, &APT_A::DoApplicationJump, "DoApplicationJump"}, | ||||||
|         {0x0033, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, |         {0x0033, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, | ||||||
|         {0x0034, nullptr, "SendDeliverArg"}, |         {0x0034, &APT_A::SendDeliverArg, "SendDeliverArg"}, | ||||||
|         {0x0035, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"}, |         {0x0035, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"}, | ||||||
|         {0x0036, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"}, |         {0x0036, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"}, | ||||||
|         {0x0037, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"}, |         {0x0037, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"}, | ||||||
|  | @ -70,8 +70,8 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | ||||||
|         {0x0039, nullptr, "PrepareToStartResidentApplet"}, |         {0x0039, nullptr, "PrepareToStartResidentApplet"}, | ||||||
|         {0x003A, nullptr, "StartResidentApplet"}, |         {0x003A, nullptr, "StartResidentApplet"}, | ||||||
|         {0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"}, |         {0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"}, | ||||||
|         {0x003C, nullptr, "SendDspSleep"}, |         {0x003C, &APT_A::SendDspSleep, "SendDspSleep"}, | ||||||
|         {0x003D, nullptr, "SendDspWakeUp"}, |         {0x003D, &APT_A::SendDspWakeUp, "SendDspWakeUp"}, | ||||||
|         {0x003E, nullptr, "ReplySleepQuery"}, |         {0x003E, nullptr, "ReplySleepQuery"}, | ||||||
|         {0x003F, nullptr, "ReplySleepNotificationComplete"}, |         {0x003F, nullptr, "ReplySleepNotificationComplete"}, | ||||||
|         {0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, |         {0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, | ||||||
|  | @ -82,26 +82,27 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | ||||||
|         {0x0045, &APT_A::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, |         {0x0045, &APT_A::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, | ||||||
|         {0x0046, &APT_A::Wrap, "Wrap"}, |         {0x0046, &APT_A::Wrap, "Wrap"}, | ||||||
|         {0x0047, &APT_A::Unwrap, "Unwrap"}, |         {0x0047, &APT_A::Unwrap, "Unwrap"}, | ||||||
|         {0x0048, nullptr, "GetProgramInfo"}, |         {0x0048, &APT_A::GetProgramInfo, "GetProgramInfo"}, | ||||||
|         {0x0049, nullptr, "Reboot"}, |         {0x0049, &APT_A::Reboot, "Reboot"}, | ||||||
|         {0x004A, &APT_A::GetCaptureInfo, "GetCaptureInfo"}, |         {0x004A, &APT_A::GetCaptureInfo, "GetCaptureInfo"}, | ||||||
|         {0x004B, &APT_A::AppletUtility, "AppletUtility"}, |         {0x004B, &APT_A::AppletUtility, "AppletUtility"}, | ||||||
|         {0x004C, nullptr, "SetFatalErrDispMode"}, |         {0x004C, nullptr, "SetFatalErrDispMode"}, | ||||||
|         {0x004D, nullptr, "GetAppletProgramInfo"}, |         {0x004D, nullptr, "GetAppletProgramInfo"}, | ||||||
|         {0x004E, nullptr, "HardwareResetAsync"}, |         {0x004E, &APT_A::HardwareResetAsync, "HardwareResetAsync"}, | ||||||
|         {0x004F, &APT_A::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, |         {0x004F, &APT_A::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||||||
|         {0x0050, &APT_A::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, |         {0x0050, &APT_A::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||||||
|         {0x0051, &APT_A::GetStartupArgument, "GetStartupArgument"}, |         {0x0051, &APT_A::GetStartupArgument, "GetStartupArgument"}, | ||||||
|         {0x0052, nullptr, "Wrap1"}, |         {0x0052, nullptr, "Wrap1"}, | ||||||
|         {0x0053, nullptr, "Unwrap1"}, |         {0x0053, nullptr, "Unwrap1"}, | ||||||
|         {0x0055, &APT_A::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, |         {0x0054, &APT_A::Unknown54, "Unknown54"}, | ||||||
|         {0x0056, &APT_A::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, |         {0x0055, &APT_A::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"}, | ||||||
|         {0x0057, nullptr, "WakeupApplication2"}, |         {0x0056, &APT_A::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"}, | ||||||
|         {0x0058, nullptr, "GetProgramID"}, |         {0x0057, &APT_A::WakeupApplication2, "WakeupApplication2"}, | ||||||
|         {0x0101, &APT_A::CheckNew3DSApp, "CheckNew3DSApp"}, |         {0x0058, &APT_A::GetProgramId, "GetProgramId"}, | ||||||
|  |         {0x0101, &APT_A::GetTargetPlatform, "GetTargetPlatform"}, | ||||||
|         {0x0102, &APT_A::CheckNew3DS, "CheckNew3DS"}, |         {0x0102, &APT_A::CheckNew3DS, "CheckNew3DS"}, | ||||||
|         {0x0103, &APT_A::Unknown0x0103, "Unknown0x0103"}, |         {0x0103, &APT_A::GetApplicationRunningMode, "GetApplicationRunningMode"}, | ||||||
|         {0x0104, nullptr, "IsStandardMemoryLayout"}, |         {0x0104, &APT_A::IsStandardMemoryLayout, "IsStandardMemoryLayout"}, | ||||||
|         {0x0105, &APT_A::IsTitleAllowed, "IsTitleAllowed"}, |         {0x0105, &APT_A::IsTitleAllowed, "IsTitleAllowed"}, | ||||||
|         // clang-format on
 |         // clang-format on
 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -14,13 +14,13 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | ||||||
|         {0x0001, &APT_S::GetLockHandle, "GetLockHandle"}, |         {0x0001, &APT_S::GetLockHandle, "GetLockHandle"}, | ||||||
|         {0x0002, &APT_S::Initialize, "Initialize"}, |         {0x0002, &APT_S::Initialize, "Initialize"}, | ||||||
|         {0x0003, &APT_S::Enable, "Enable"}, |         {0x0003, &APT_S::Enable, "Enable"}, | ||||||
|         {0x0004, nullptr, "Finalize"}, |         {0x0004, &APT_S::Finalize, "Finalize"}, | ||||||
|         {0x0005, &APT_S::GetAppletManInfo, "GetAppletManInfo"}, |         {0x0005, &APT_S::GetAppletManInfo, "GetAppletManInfo"}, | ||||||
|         {0x0006, &APT_S::GetAppletInfo, "GetAppletInfo"}, |         {0x0006, &APT_S::GetAppletInfo, "GetAppletInfo"}, | ||||||
|         {0x0007, nullptr, "GetLastSignaledAppletId"}, |         {0x0007, nullptr, "GetLastSignaledAppletId"}, | ||||||
|         {0x0008, nullptr, "CountRegisteredApplet"}, |         {0x0008, &APT_S::CountRegisteredApplet, "CountRegisteredApplet"}, | ||||||
|         {0x0009, &APT_S::IsRegistered, "IsRegistered"}, |         {0x0009, &APT_S::IsRegistered, "IsRegistered"}, | ||||||
|         {0x000A, nullptr, "GetAttribute"}, |         {0x000A, &APT_S::GetAttribute, "GetAttribute"}, | ||||||
|         {0x000B, &APT_S::InquireNotification, "InquireNotification"}, |         {0x000B, &APT_S::InquireNotification, "InquireNotification"}, | ||||||
|         {0x000C, &APT_S::SendParameter, "SendParameter"}, |         {0x000C, &APT_S::SendParameter, "SendParameter"}, | ||||||
|         {0x000D, &APT_S::ReceiveParameter, "ReceiveParameter"}, |         {0x000D, &APT_S::ReceiveParameter, "ReceiveParameter"}, | ||||||
|  | @ -39,7 +39,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | ||||||
|         {0x001A, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, |         {0x001A, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, | ||||||
|         {0x001B, &APT_S::StartApplication, "StartApplication"}, |         {0x001B, &APT_S::StartApplication, "StartApplication"}, | ||||||
|         {0x001C, &APT_S::WakeupApplication, "WakeupApplication"}, |         {0x001C, &APT_S::WakeupApplication, "WakeupApplication"}, | ||||||
|         {0x001D, nullptr, "CancelApplication"}, |         {0x001D, &APT_S::CancelApplication, "CancelApplication"}, | ||||||
|         {0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"}, |         {0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"}, | ||||||
|         {0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"}, |         {0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"}, | ||||||
|         {0x0020, nullptr, "StartNewestHomeMenu"}, |         {0x0020, nullptr, "StartNewestHomeMenu"}, | ||||||
|  | @ -62,7 +62,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | ||||||
|         {0x0031, &APT_S::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, |         {0x0031, &APT_S::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, | ||||||
|         {0x0032, &APT_S::DoApplicationJump, "DoApplicationJump"}, |         {0x0032, &APT_S::DoApplicationJump, "DoApplicationJump"}, | ||||||
|         {0x0033, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, |         {0x0033, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, | ||||||
|         {0x0034, nullptr, "SendDeliverArg"}, |         {0x0034, &APT_S::SendDeliverArg, "SendDeliverArg"}, | ||||||
|         {0x0035, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"}, |         {0x0035, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"}, | ||||||
|         {0x0036, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"}, |         {0x0036, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"}, | ||||||
|         {0x0037, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"}, |         {0x0037, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"}, | ||||||
|  | @ -70,8 +70,8 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | ||||||
|         {0x0039, nullptr, "PrepareToStartResidentApplet"}, |         {0x0039, nullptr, "PrepareToStartResidentApplet"}, | ||||||
|         {0x003A, nullptr, "StartResidentApplet"}, |         {0x003A, nullptr, "StartResidentApplet"}, | ||||||
|         {0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"}, |         {0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"}, | ||||||
|         {0x003C, nullptr, "SendDspSleep"}, |         {0x003C, &APT_S::SendDspSleep, "SendDspSleep"}, | ||||||
|         {0x003D, nullptr, "SendDspWakeUp"}, |         {0x003D, &APT_S::SendDspWakeUp, "SendDspWakeUp"}, | ||||||
|         {0x003E, nullptr, "ReplySleepQuery"}, |         {0x003E, nullptr, "ReplySleepQuery"}, | ||||||
|         {0x003F, nullptr, "ReplySleepNotificationComplete"}, |         {0x003F, nullptr, "ReplySleepNotificationComplete"}, | ||||||
|         {0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, |         {0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, | ||||||
|  | @ -82,26 +82,27 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | ||||||
|         {0x0045, &APT_S::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, |         {0x0045, &APT_S::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, | ||||||
|         {0x0046, &APT_S::Wrap, "Wrap"}, |         {0x0046, &APT_S::Wrap, "Wrap"}, | ||||||
|         {0x0047, &APT_S::Unwrap, "Unwrap"}, |         {0x0047, &APT_S::Unwrap, "Unwrap"}, | ||||||
|         {0x0048, nullptr, "GetProgramInfo"}, |         {0x0048, &APT_S::GetProgramInfo, "GetProgramInfo"}, | ||||||
|         {0x0049, nullptr, "Reboot"}, |         {0x0049, &APT_S::Reboot, "Reboot"}, | ||||||
|         {0x004A, &APT_S::GetCaptureInfo, "GetCaptureInfo"}, |         {0x004A, &APT_S::GetCaptureInfo, "GetCaptureInfo"}, | ||||||
|         {0x004B, &APT_S::AppletUtility, "AppletUtility"}, |         {0x004B, &APT_S::AppletUtility, "AppletUtility"}, | ||||||
|         {0x004C, nullptr, "SetFatalErrDispMode"}, |         {0x004C, nullptr, "SetFatalErrDispMode"}, | ||||||
|         {0x004D, nullptr, "GetAppletProgramInfo"}, |         {0x004D, nullptr, "GetAppletProgramInfo"}, | ||||||
|         {0x004E, nullptr, "HardwareResetAsync"}, |         {0x004E, &APT_S::HardwareResetAsync, "HardwareResetAsync"}, | ||||||
|         {0x004F, &APT_S::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, |         {0x004F, &APT_S::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||||||
|         {0x0050, &APT_S::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, |         {0x0050, &APT_S::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||||||
|         {0x0051, &APT_S::GetStartupArgument, "GetStartupArgument"}, |         {0x0051, &APT_S::GetStartupArgument, "GetStartupArgument"}, | ||||||
|         {0x0052, nullptr, "Wrap1"}, |         {0x0052, nullptr, "Wrap1"}, | ||||||
|         {0x0053, nullptr, "Unwrap1"}, |         {0x0053, nullptr, "Unwrap1"}, | ||||||
|         {0x0055, &APT_S::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, |         {0x0054, &APT_S::Unknown54, "Unknown54"}, | ||||||
|         {0x0056, &APT_S::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, |         {0x0055, &APT_S::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"}, | ||||||
|         {0x0057, nullptr, "WakeupApplication2"}, |         {0x0056, &APT_S::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"}, | ||||||
|         {0x0058, nullptr, "GetProgramID"}, |         {0x0057, &APT_S::WakeupApplication2, "WakeupApplication2"}, | ||||||
|         {0x0101, &APT_S::CheckNew3DSApp, "CheckNew3DSApp"}, |         {0x0058, &APT_S::GetProgramId, "GetProgramId"}, | ||||||
|  |         {0x0101, &APT_S::GetTargetPlatform, "GetTargetPlatform"}, | ||||||
|         {0x0102, &APT_S::CheckNew3DS, "CheckNew3DS"}, |         {0x0102, &APT_S::CheckNew3DS, "CheckNew3DS"}, | ||||||
|         {0x0103, &APT_S::Unknown0x0103, "Unknown0x0103"}, |         {0x0103, &APT_S::GetApplicationRunningMode, "GetApplicationRunningMode"}, | ||||||
|         {0x0104, nullptr, "IsStandardMemoryLayout"}, |         {0x0104, &APT_S::IsStandardMemoryLayout, "IsStandardMemoryLayout"}, | ||||||
|         {0x0105, &APT_S::IsTitleAllowed, "IsTitleAllowed"}, |         {0x0105, &APT_S::IsTitleAllowed, "IsTitleAllowed"}, | ||||||
|         // clang-format on
 |         // clang-format on
 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -14,13 +14,13 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | ||||||
|         {0x0001, &APT_U::GetLockHandle, "GetLockHandle"}, |         {0x0001, &APT_U::GetLockHandle, "GetLockHandle"}, | ||||||
|         {0x0002, &APT_U::Initialize, "Initialize"}, |         {0x0002, &APT_U::Initialize, "Initialize"}, | ||||||
|         {0x0003, &APT_U::Enable, "Enable"}, |         {0x0003, &APT_U::Enable, "Enable"}, | ||||||
|         {0x0004, nullptr, "Finalize"}, |         {0x0004, &APT_U::Finalize, "Finalize"}, | ||||||
|         {0x0005, &APT_U::GetAppletManInfo, "GetAppletManInfo"}, |         {0x0005, &APT_U::GetAppletManInfo, "GetAppletManInfo"}, | ||||||
|         {0x0006, &APT_U::GetAppletInfo, "GetAppletInfo"}, |         {0x0006, &APT_U::GetAppletInfo, "GetAppletInfo"}, | ||||||
|         {0x0007, nullptr, "GetLastSignaledAppletId"}, |         {0x0007, nullptr, "GetLastSignaledAppletId"}, | ||||||
|         {0x0008, nullptr, "CountRegisteredApplet"}, |         {0x0008, &APT_U::CountRegisteredApplet, "CountRegisteredApplet"}, | ||||||
|         {0x0009, &APT_U::IsRegistered, "IsRegistered"}, |         {0x0009, &APT_U::IsRegistered, "IsRegistered"}, | ||||||
|         {0x000A, nullptr, "GetAttribute"}, |         {0x000A, &APT_U::GetAttribute, "GetAttribute"}, | ||||||
|         {0x000B, &APT_U::InquireNotification, "InquireNotification"}, |         {0x000B, &APT_U::InquireNotification, "InquireNotification"}, | ||||||
|         {0x000C, &APT_U::SendParameter, "SendParameter"}, |         {0x000C, &APT_U::SendParameter, "SendParameter"}, | ||||||
|         {0x000D, &APT_U::ReceiveParameter, "ReceiveParameter"}, |         {0x000D, &APT_U::ReceiveParameter, "ReceiveParameter"}, | ||||||
|  | @ -39,7 +39,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | ||||||
|         {0x001A, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, |         {0x001A, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, | ||||||
|         {0x001B, &APT_U::StartApplication, "StartApplication"}, |         {0x001B, &APT_U::StartApplication, "StartApplication"}, | ||||||
|         {0x001C, &APT_U::WakeupApplication, "WakeupApplication"}, |         {0x001C, &APT_U::WakeupApplication, "WakeupApplication"}, | ||||||
|         {0x001D, nullptr, "CancelApplication"}, |         {0x001D, &APT_U::CancelApplication, "CancelApplication"}, | ||||||
|         {0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"}, |         {0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"}, | ||||||
|         {0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"}, |         {0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"}, | ||||||
|         {0x0020, nullptr, "StartNewestHomeMenu"}, |         {0x0020, nullptr, "StartNewestHomeMenu"}, | ||||||
|  | @ -62,7 +62,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | ||||||
|         {0x0031, &APT_U::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, |         {0x0031, &APT_U::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, | ||||||
|         {0x0032, &APT_U::DoApplicationJump, "DoApplicationJump"}, |         {0x0032, &APT_U::DoApplicationJump, "DoApplicationJump"}, | ||||||
|         {0x0033, &APT_U::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, |         {0x0033, &APT_U::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, | ||||||
|         {0x0034, nullptr, "SendDeliverArg"}, |         {0x0034, &APT_U::SendDeliverArg, "SendDeliverArg"}, | ||||||
|         {0x0035, &APT_U::ReceiveDeliverArg, "ReceiveDeliverArg"}, |         {0x0035, &APT_U::ReceiveDeliverArg, "ReceiveDeliverArg"}, | ||||||
|         {0x0036, &APT_U::LoadSysMenuArg, "LoadSysMenuArg"}, |         {0x0036, &APT_U::LoadSysMenuArg, "LoadSysMenuArg"}, | ||||||
|         {0x0037, &APT_U::StoreSysMenuArg, "StoreSysMenuArg"}, |         {0x0037, &APT_U::StoreSysMenuArg, "StoreSysMenuArg"}, | ||||||
|  | @ -70,8 +70,8 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | ||||||
|         {0x0039, nullptr, "PrepareToStartResidentApplet"}, |         {0x0039, nullptr, "PrepareToStartResidentApplet"}, | ||||||
|         {0x003A, nullptr, "StartResidentApplet"}, |         {0x003A, nullptr, "StartResidentApplet"}, | ||||||
|         {0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"}, |         {0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"}, | ||||||
|         {0x003C, nullptr, "SendDspSleep"}, |         {0x003C, &APT_U::SendDspSleep, "SendDspSleep"}, | ||||||
|         {0x003D, nullptr, "SendDspWakeUp"}, |         {0x003D, &APT_U::SendDspWakeUp, "SendDspWakeUp"}, | ||||||
|         {0x003E, nullptr, "ReplySleepQuery"}, |         {0x003E, nullptr, "ReplySleepQuery"}, | ||||||
|         {0x003F, nullptr, "ReplySleepNotificationComplete"}, |         {0x003F, nullptr, "ReplySleepNotificationComplete"}, | ||||||
|         {0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, |         {0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, | ||||||
|  | @ -82,26 +82,27 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | ||||||
|         {0x0045, &APT_U::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, |         {0x0045, &APT_U::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, | ||||||
|         {0x0046, &APT_U::Wrap, "Wrap"}, |         {0x0046, &APT_U::Wrap, "Wrap"}, | ||||||
|         {0x0047, &APT_U::Unwrap, "Unwrap"}, |         {0x0047, &APT_U::Unwrap, "Unwrap"}, | ||||||
|         {0x0048, nullptr, "GetProgramInfo"}, |         {0x0048, &APT_U::GetProgramInfo, "GetProgramInfo"}, | ||||||
|         {0x0049, nullptr, "Reboot"}, |         {0x0049, &APT_U::Reboot, "Reboot"}, | ||||||
|         {0x004A, &APT_U::GetCaptureInfo, "GetCaptureInfo"}, |         {0x004A, &APT_U::GetCaptureInfo, "GetCaptureInfo"}, | ||||||
|         {0x004B, &APT_U::AppletUtility, "AppletUtility"}, |         {0x004B, &APT_U::AppletUtility, "AppletUtility"}, | ||||||
|         {0x004C, nullptr, "SetFatalErrDispMode"}, |         {0x004C, nullptr, "SetFatalErrDispMode"}, | ||||||
|         {0x004D, nullptr, "GetAppletProgramInfo"}, |         {0x004D, nullptr, "GetAppletProgramInfo"}, | ||||||
|         {0x004E, nullptr, "HardwareResetAsync"}, |         {0x004E, &APT_U::HardwareResetAsync, "HardwareResetAsync"}, | ||||||
|         {0x004F, &APT_U::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, |         {0x004F, &APT_U::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||||||
|         {0x0050, &APT_U::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, |         {0x0050, &APT_U::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||||||
|         {0x0051, &APT_U::GetStartupArgument, "GetStartupArgument"}, |         {0x0051, &APT_U::GetStartupArgument, "GetStartupArgument"}, | ||||||
|         {0x0052, nullptr, "Wrap1"}, |         {0x0052, nullptr, "Wrap1"}, | ||||||
|         {0x0053, nullptr, "Unwrap1"}, |         {0x0053, nullptr, "Unwrap1"}, | ||||||
|         {0x0055, &APT_U::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, |         {0x0054, &APT_U::Unknown54, "Unknown54"}, | ||||||
|         {0x0056, &APT_U::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, |         {0x0055, &APT_U::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"}, | ||||||
|         {0x0057, nullptr, "WakeupApplication2"}, |         {0x0056, &APT_U::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"}, | ||||||
|         {0x0058, nullptr, "GetProgramID"}, |         {0x0057, &APT_U::WakeupApplication2, "WakeupApplication2"}, | ||||||
|         {0x0101, &APT_U::CheckNew3DSApp, "CheckNew3DSApp"}, |         {0x0058, &APT_U::GetProgramId, "GetProgramId"}, | ||||||
|  |         {0x0101, &APT_U::GetTargetPlatform, "GetTargetPlatform"}, | ||||||
|         {0x0102, &APT_U::CheckNew3DS, "CheckNew3DS"}, |         {0x0102, &APT_U::CheckNew3DS, "CheckNew3DS"}, | ||||||
|         {0x0103, &APT_U::Unknown0x0103, "Unknown0x0103"}, |         {0x0103, &APT_U::GetApplicationRunningMode, "GetApplicationRunningMode"}, | ||||||
|         {0x0104, nullptr, "IsStandardMemoryLayout"}, |         {0x0104, &APT_U::IsStandardMemoryLayout, "IsStandardMemoryLayout"}, | ||||||
|         {0x0105, &APT_U::IsTitleAllowed, "IsTitleAllowed"}, |         {0x0105, &APT_U::IsTitleAllowed, "IsTitleAllowed"}, | ||||||
|         // clang-format on
 |         // clang-format on
 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -8,5 +8,6 @@ namespace Service::APT::ErrCodes { | ||||||
| enum { | enum { | ||||||
|     ParameterPresent = 2, |     ParameterPresent = 2, | ||||||
|     InvalidAppletSlot = 4, |     InvalidAppletSlot = 4, | ||||||
|  |     AppNotRunning = 11, | ||||||
| }; | }; | ||||||
| } // namespace Service::APT::ErrCodes
 | } // namespace Service::APT::ErrCodes
 | ||||||
|  |  | ||||||
|  | @ -29,4 +29,17 @@ std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title | ||||||
|     return process; |     return process; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id) { | ||||||
|  |     auto new_path = AM::GetTitleContentPath(media_type, title_id); | ||||||
|  |     if (new_path.empty() || !FileUtil::Exists(new_path)) { | ||||||
|  |         // TODO: This can happen if the requested title is not installed. Need a way to find
 | ||||||
|  |         // non-installed titles in the game list.
 | ||||||
|  |         LOG_CRITICAL(Service_APT, | ||||||
|  |                      "Failed to find title '{}' to jump to, resetting current title instead.", | ||||||
|  |                      new_path); | ||||||
|  |         new_path.clear(); | ||||||
|  |     } | ||||||
|  |     system.RequestReset(new_path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace Service::NS
 | } // namespace Service::NS
 | ||||||
|  |  | ||||||
|  | @ -18,4 +18,7 @@ namespace Service::NS { | ||||||
| /// Loads and launches the title identified by title_id in the specified media type.
 | /// Loads and launches the title identified by title_id in the specified media type.
 | ||||||
| std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title_id); | std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title_id); | ||||||
| 
 | 
 | ||||||
|  | /// Reboots the system to the specified title.
 | ||||||
|  | void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id); | ||||||
|  | 
 | ||||||
| } // namespace Service::NS
 | } // namespace Service::NS
 | ||||||
|  |  | ||||||
|  | @ -672,30 +672,23 @@ void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
| void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) { | void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx); |     IPC::RequestParser rp(ctx); | ||||||
| 
 |     const auto process_id = rp.Pop<u32>(); | ||||||
|     u32 process_id = rp.Pop<u32>(); |  | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_FS, "process_id={}", process_id); |     LOG_DEBUG(Service_FS, "process_id={}", process_id); | ||||||
| 
 | 
 | ||||||
|     auto program_info = program_info_map.find(process_id); |  | ||||||
| 
 |  | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); | ||||||
| 
 | 
 | ||||||
|     if (program_info == program_info_map.end()) { |     auto program_info_result = GetProgramLaunchInfo(process_id); | ||||||
|  |     if (program_info_result.Failed()) { | ||||||
|         // Note: In this case, the rest of the parameters are not changed but the command header
 |         // Note: In this case, the rest of the parameters are not changed but the command header
 | ||||||
|         // remains the same.
 |         // remains the same.
 | ||||||
|         rb.Push(ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS, |         rb.Push(program_info_result.Code()); | ||||||
|                            ErrorSummary::NotFound, ErrorLevel::Status)); |  | ||||||
|         rb.Skip(4, false); |         rb.Skip(4, false); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.Push(program_info->second.program_id); |     rb.PushRaw(program_info_result.Unwrap()); | ||||||
|     rb.Push(static_cast<u8>(program_info->second.media_type)); |  | ||||||
| 
 |  | ||||||
|     // TODO(Subv): Find out what this value means.
 |  | ||||||
|     rb.Push<u32>(0); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) { | void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) { | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| #include <boost/serialization/base_object.hpp> | #include <boost/serialization/base_object.hpp> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "core/file_sys/errors.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
|  | @ -17,6 +18,13 @@ namespace Service::FS { | ||||||
| 
 | 
 | ||||||
| class ArchiveManager; | class ArchiveManager; | ||||||
| 
 | 
 | ||||||
|  | struct ProgramInfo { | ||||||
|  |     u64 program_id; | ||||||
|  |     MediaType media_type; | ||||||
|  |     INSERT_PADDING_BYTES(4); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ProgramInfo) == 0x10, "ProgramInfo struct has incorrect size"); | ||||||
|  | 
 | ||||||
| struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase { | struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase { | ||||||
|     // We retrieves program ID for client process on FS::Initialize(WithSDKVersion)
 |     // We retrieves program ID for client process on FS::Initialize(WithSDKVersion)
 | ||||||
|     // Real 3DS matches program ID and process ID based on data registered by loader via fs:REG, so
 |     // Real 3DS matches program ID and process ID based on data registered by loader via fs:REG, so
 | ||||||
|  | @ -45,6 +53,17 @@ public: | ||||||
| 
 | 
 | ||||||
|     std::string GetCurrentGamecardPath() const; |     std::string GetCurrentGamecardPath() const; | ||||||
| 
 | 
 | ||||||
|  |     /// Gets the registered program info of a process.
 | ||||||
|  |     ResultVal<ProgramInfo> GetProgramLaunchInfo(u32 process_id) const { | ||||||
|  |         auto info = program_info_map.find(process_id); | ||||||
|  |         if (info != program_info_map.end()) { | ||||||
|  |             return info->second; | ||||||
|  |         } else { | ||||||
|  |             return ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS, | ||||||
|  |                               ErrorSummary::NotFound, ErrorLevel::Status); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     void Initialize(Kernel::HLERequestContext& ctx); |     void Initialize(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|  | @ -602,11 +621,6 @@ private: | ||||||
|     static ResultVal<u16> GetSpecialContentIndexFromTMD(MediaType media_type, u64 title_id, |     static ResultVal<u16> GetSpecialContentIndexFromTMD(MediaType media_type, u64 title_id, | ||||||
|                                                         SpecialContentType type); |                                                         SpecialContentType type); | ||||||
| 
 | 
 | ||||||
|     struct ProgramInfo { |  | ||||||
|         u64 program_id; |  | ||||||
|         MediaType media_type; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     std::unordered_map<u32, ProgramInfo> program_info_map; |     std::unordered_map<u32, ProgramInfo> program_info_map; | ||||||
|     std::string current_gamecard_path; |     std::string current_gamecard_path; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "core/file_sys/romfs_reader.h" | #include "core/file_sys/romfs_reader.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/hle/kernel/object.h" | #include "core/hle/kernel/object.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
|  | @ -99,23 +100,36 @@ public: | ||||||
|     virtual ResultStatus Load(std::shared_ptr<Kernel::Process>& process) = 0; |     virtual ResultStatus Load(std::shared_ptr<Kernel::Process>& process) = 0; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Loads the system mode that this application needs. |      * Loads the core version (FIRM title ID low) that this application needs. | ||||||
|      * This function defaults to 2 (96MB allocated to the application) if it can't read the |      * This function defaults to 0x2 (NATIVE_FIRM) if it can't read the | ||||||
|      * information. |      * information. | ||||||
|      * @returns A pair with the optional system mode, and the status. |      * @returns A pair with the optional core version, and the status. | ||||||
|      */ |      */ | ||||||
|     virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() { |     virtual std::pair<std::optional<u32>, ResultStatus> LoadCoreVersion() { | ||||||
|         // 96MB allocated to the application.
 |         return std::make_pair(0x2, ResultStatus::Success); | ||||||
|         return std::make_pair(2, ResultStatus::Success); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Loads the N3ds mode that this application uses. |      * Loads the memory mode that this application needs. | ||||||
|      * It defaults to 0 (O3DS default) if it can't read the information. |      * This function defaults to Dev1 (96MB allocated to the application) if it can't read the | ||||||
|      * @returns A pair with the optional N3ds mode, and the status. |      * information. | ||||||
|  |      * @returns A pair with the optional memory mode, and the status. | ||||||
|      */ |      */ | ||||||
|     virtual std::pair<std::optional<u8>, ResultStatus> LoadKernelN3dsMode() { |     virtual std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> LoadKernelMemoryMode() { | ||||||
|         return std::make_pair(u8(0), ResultStatus::Success); |         // 96MB allocated to the application.
 | ||||||
|  |         return std::make_pair(Kernel::MemoryMode::Dev1, ResultStatus::Success); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Loads the N3DS hardware capabilities that this application uses. | ||||||
|  |      * It defaults to all disabled (O3DS) if it can't read the information. | ||||||
|  |      * @returns A pair with the optional N3DS hardware capabilities, and the status. | ||||||
|  |      */ | ||||||
|  |     virtual std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> | ||||||
|  |     LoadNew3dsHwCapabilities() { | ||||||
|  |         return std::make_pair( | ||||||
|  |             Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}, | ||||||
|  |             ResultStatus::Success); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/file_sys/ncch_container.h" | #include "core/file_sys/ncch_container.h" | ||||||
| #include "core/file_sys/title_metadata.h" | #include "core/file_sys/title_metadata.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/resource_limit.h" | #include "core/hle/kernel/resource_limit.h" | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
|  | @ -47,7 +48,7 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) { | ||||||
|     return FileType::Error; |     return FileType::Error; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() { | std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadCoreVersion() { | ||||||
|     if (!is_loaded) { |     if (!is_loaded) { | ||||||
|         ResultStatus res = base_ncch.Load(); |         ResultStatus res = base_ncch.Load(); | ||||||
|         if (res != ResultStatus::Success) { |         if (res != ResultStatus::Success) { | ||||||
|  | @ -55,12 +56,12 @@ std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Set the system mode as the one from the exheader.
 |     // Provide the core version from the exheader.
 | ||||||
|     return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.system_mode.Value(), |     auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps; | ||||||
|                           ResultStatus::Success); |     return std::make_pair(ncch_caps.core_version, ResultStatus::Success); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::pair<std::optional<u8>, ResultStatus> AppLoader_NCCH::LoadKernelN3dsMode() { | std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> AppLoader_NCCH::LoadKernelMemoryMode() { | ||||||
|     if (!is_loaded) { |     if (!is_loaded) { | ||||||
|         ResultStatus res = base_ncch.Load(); |         ResultStatus res = base_ncch.Load(); | ||||||
|         if (res != ResultStatus::Success) { |         if (res != ResultStatus::Success) { | ||||||
|  | @ -68,9 +69,29 @@ std::pair<std::optional<u8>, ResultStatus> AppLoader_NCCH::LoadKernelN3dsMode() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Set the system mode as the one from the exheader.
 |     // Provide the memory mode from the exheader.
 | ||||||
|     return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.n3ds_mode, |     auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps; | ||||||
|                           ResultStatus::Success); |     auto mode = static_cast<Kernel::MemoryMode>(ncch_caps.system_mode.Value()); | ||||||
|  |     return std::make_pair(mode, ResultStatus::Success); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> | ||||||
|  | AppLoader_NCCH::LoadNew3dsHwCapabilities() { | ||||||
|  |     if (!is_loaded) { | ||||||
|  |         ResultStatus res = base_ncch.Load(); | ||||||
|  |         if (res != ResultStatus::Success) { | ||||||
|  |             return std::make_pair(std::nullopt, res); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Provide the capabilities from the exheader.
 | ||||||
|  |     auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps; | ||||||
|  |     auto caps = Kernel::New3dsHwCapabilities{ | ||||||
|  |         ncch_caps.enable_l2_cache != 0, | ||||||
|  |         ncch_caps.enable_804MHz_cpu != 0, | ||||||
|  |         static_cast<Kernel::New3dsMemoryMode>(ncch_caps.n3ds_mode), | ||||||
|  |     }; | ||||||
|  |     return std::make_pair(std::move(caps), ResultStatus::Success); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) { | ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) { | ||||||
|  |  | ||||||
|  | @ -32,13 +32,16 @@ public: | ||||||
| 
 | 
 | ||||||
|     ResultStatus Load(std::shared_ptr<Kernel::Process>& process) override; |     ResultStatus Load(std::shared_ptr<Kernel::Process>& process) override; | ||||||
| 
 | 
 | ||||||
|  |     std::pair<std::optional<u32>, ResultStatus> LoadCoreVersion() override; | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Loads the Exheader and returns the system mode for this application. |      * Loads the Exheader and returns the system mode for this application. | ||||||
|      * @returns A pair with the optional system mode, and and the status. |      * @returns A pair with the optional system mode, and and the status. | ||||||
|      */ |      */ | ||||||
|     std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() override; |     std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> LoadKernelMemoryMode() override; | ||||||
| 
 | 
 | ||||||
|     std::pair<std::optional<u8>, ResultStatus> LoadKernelN3dsMode() override; |     std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities() | ||||||
|  |         override; | ||||||
| 
 | 
 | ||||||
|     ResultStatus IsExecutable(bool& out_executable) override; |     ResultStatus IsExecutable(bool& out_executable) override; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,7 +18,8 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) | ||||||
|     timing = std::make_unique<Core::Timing>(1, 100); |     timing = std::make_unique<Core::Timing>(1, 100); | ||||||
|     memory = std::make_unique<Memory::MemorySystem>(); |     memory = std::make_unique<Memory::MemorySystem>(); | ||||||
|     kernel = std::make_unique<Kernel::KernelSystem>( |     kernel = std::make_unique<Kernel::KernelSystem>( | ||||||
|         *memory, *timing, [] {}, 0, 1, 0); |         *memory, *timing, [] {}, Kernel::MemoryMode::Prod, 1, | ||||||
|  |         Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); | ||||||
| 
 | 
 | ||||||
|     kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0))); |     kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0))); | ||||||
|     page_table = kernel->GetCurrentProcess()->vm_manager.page_table; |     page_table = kernel->GetCurrentProcess()->vm_manager.page_table; | ||||||
|  |  | ||||||
|  | @ -25,7 +25,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | ||||||
|     Core::Timing timing(1, 100); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel( |     Kernel::KernelSystem kernel( | ||||||
|         memory, timing, [] {}, 0, 1, 0); |         memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, | ||||||
|  |         Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); | ||||||
|     auto [server, client] = kernel.CreateSessionPair(); |     auto [server, client] = kernel.CreateSessionPair(); | ||||||
|     HLERequestContext context(kernel, std::move(server), nullptr); |     HLERequestContext context(kernel, std::move(server), nullptr); | ||||||
| 
 | 
 | ||||||
|  | @ -248,7 +249,8 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | ||||||
|     Core::Timing timing(1, 100); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel( |     Kernel::KernelSystem kernel( | ||||||
|         memory, timing, [] {}, 0, 1, 0); |         memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, | ||||||
|  |         Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); | ||||||
|     auto [server, client] = kernel.CreateSessionPair(); |     auto [server, client] = kernel.CreateSessionPair(); | ||||||
|     HLERequestContext context(kernel, std::move(server), nullptr); |     HLERequestContext context(kernel, std::move(server), nullptr); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,7 +11,8 @@ TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") { | ||||||
|     Core::Timing timing(1, 100); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel( |     Kernel::KernelSystem kernel( | ||||||
|         memory, timing, [] {}, 0, 1, 0); |         memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, | ||||||
|  |         Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); | ||||||
|     SECTION("these regions should not be mapped on an empty process") { |     SECTION("these regions should not be mapped on an empty process") { | ||||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); |         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||||
|         CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); | ||||||
|  |  | ||||||
|  | @ -17,7 +17,8 @@ TEST_CASE("Memory Basics", "[kernel][memory]") { | ||||||
|     Core::Timing timing(1, 100); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel( |     Kernel::KernelSystem kernel( | ||||||
|         memory, timing, [] {}, 0, 1, 0); |         memory, timing, [] {}, Kernel::MemoryMode::Prod, 1, | ||||||
|  |         Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}); | ||||||
|     Kernel::Process process(kernel); |     Kernel::Process process(kernel); | ||||||
|     SECTION("mapping memory") { |     SECTION("mapping memory") { | ||||||
|         // Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
 |         // Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue