mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30: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 = { | ||||
|     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_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{{ | ||||
|  |  | |||
|  | @ -162,7 +162,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|         ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, | ||||
|         ui->buttonL,      ui->buttonR,        ui->buttonStart,    ui->buttonSelect, | ||||
|         ui->buttonDebug,  ui->buttonGpio14,   ui->buttonZL,       ui->buttonZR, | ||||
|         ui->buttonHome, | ||||
|         ui->buttonHome,   ui->buttonPower, | ||||
|     }; | ||||
| 
 | ||||
|     analog_map_buttons = {{ | ||||
|  |  | |||
|  | @ -305,6 +305,24 @@ | |||
|          </layout> | ||||
|         </item> | ||||
|         <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"> | ||||
|           <item> | ||||
|            <widget class="QLabel" name="label_36"> | ||||
|  | @ -340,7 +358,7 @@ | |||
|           </item> | ||||
|          </layout> | ||||
|         </item> | ||||
|         <item row="2" column="0"> | ||||
|         <item row="3" column="0"> | ||||
|          <layout class="QVBoxLayout" name="verticalLayout_32"> | ||||
|           <item> | ||||
|            <widget class="QLabel" name="label_40"> | ||||
|  |  | |||
|  | @ -100,13 +100,14 @@ enum Values { | |||
|     ZR, | ||||
| 
 | ||||
|     Home, | ||||
|     Power, | ||||
| 
 | ||||
|     NumButtons, | ||||
| }; | ||||
| 
 | ||||
| constexpr int BUTTON_HID_BEGIN = A; | ||||
| 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_IR_END = BUTTON_NS_BEGIN; | ||||
|  | @ -134,6 +135,7 @@ static const std::array<const char*, NumButtons> mapping = {{ | |||
|     "button_zl", | ||||
|     "button_zr", | ||||
|     "button_home", | ||||
|     "button_power", | ||||
| }}; | ||||
| 
 | ||||
| } // 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); | ||||
|         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 {})!", | ||||
|                      static_cast<int>(system_mode.second)); | ||||
|                      static_cast<int>(memory_mode.second)); | ||||
| 
 | ||||
|         switch (system_mode.second) { | ||||
|         switch (memory_mode.second) { | ||||
|         case Loader::ResultStatus::ErrorEncrypted: | ||||
|             return ResultStatus::ErrorLoader_ErrorEncrypted; | ||||
|         case Loader::ResultStatus::ErrorInvalidFormat: | ||||
|  | @ -278,15 +277,15 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ASSERT(system_mode.first); | ||||
|     auto n3ds_mode = app_loader->LoadKernelN3dsMode(); | ||||
|     ASSERT(n3ds_mode.first); | ||||
|     ASSERT(memory_mode.first); | ||||
|     auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities(); | ||||
|     ASSERT(n3ds_hw_caps.first); | ||||
|     u32 num_cores = 2; | ||||
|     if (Settings::values.is_new_3ds) { | ||||
|         num_cores = 4; | ||||
|     } | ||||
|     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) { | ||||
|         LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", | ||||
|                      static_cast<u32>(init_result)); | ||||
|  | @ -363,8 +362,9 @@ void System::Reschedule() { | |||
| } | ||||
| 
 | ||||
| System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, | ||||
|                                   Frontend::EmuWindow* secondary_window, u32 system_mode, | ||||
|                                   u8 n3ds_mode, u32 num_cores) { | ||||
|                                   Frontend::EmuWindow* secondary_window, | ||||
|                                   Kernel::MemoryMode memory_mode, | ||||
|                                   const Kernel::New3dsHwCapabilities& n3ds_hw_caps, u32 num_cores) { | ||||
|     LOG_DEBUG(HW_Memory, "initialized OK"); | ||||
| 
 | ||||
|     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()); | ||||
| 
 | ||||
|     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); | ||||
|     cpu_cores.reserve(num_cores); | ||||
|  | @ -673,10 +673,10 @@ void System::serialize(Archive& ar, const unsigned int file_version) { | |||
|         Shutdown(true); | ||||
| 
 | ||||
|         // Re-initialize everything like it was before
 | ||||
|         auto system_mode = this->app_loader->LoadKernelSystemMode(); | ||||
|         auto n3ds_mode = this->app_loader->LoadKernelN3dsMode(); | ||||
|         auto memory_mode = this->app_loader->LoadKernelMemoryMode(); | ||||
|         auto n3ds_hw_caps = this->app_loader->LoadNew3dsHwCapabilities(); | ||||
|         [[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
 | ||||
|  |  | |||
|  | @ -342,8 +342,10 @@ private: | |||
|      * @return ResultStatus code, indicating if the operation succeeded. | ||||
|      */ | ||||
|     [[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window, | ||||
|                                     Frontend::EmuWindow* secondary_window, u32 system_mode, | ||||
|                                     u8 n3ds_mode, u32 num_cores); | ||||
|                                     Frontend::EmuWindow* secondary_window, | ||||
|                                     Kernel::MemoryMode memory_mode, | ||||
|                                     const Kernel::New3dsHwCapabilities& n3ds_hw_caps, | ||||
|                                     u32 num_cores); | ||||
| 
 | ||||
|     /// Reschedule the core emulation
 | ||||
|     void Reschedule(); | ||||
|  |  | |||
|  | @ -165,7 +165,11 @@ struct ExHeader_StorageInfo { | |||
| struct ExHeader_ARM11_SystemLocalCaps { | ||||
|     u64_le program_id; | ||||
|     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; | ||||
|     union { | ||||
|         u8 flags0; | ||||
|  |  | |||
|  | @ -23,13 +23,15 @@ namespace Kernel { | |||
| 
 | ||||
| /// Initialize the kernel
 | ||||
| KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, | ||||
|                            std::function<void()> prepare_reschedule_callback, u32 system_mode, | ||||
|                            u32 num_cores, u8 n3ds_mode) | ||||
|                            std::function<void()> prepare_reschedule_callback, | ||||
|                            MemoryMode memory_mode, u32 num_cores, | ||||
|                            const New3dsHwCapabilities& n3ds_hw_caps) | ||||
|     : 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(), | ||||
|                   [] { 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); | ||||
|     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& stored_processes; | ||||
|     ar& next_thread_id; | ||||
|     ar& memory_mode; | ||||
|     ar& n3ds_hw_caps; | ||||
|     // Deliberately don't include debugger info to allow debugging through loads
 | ||||
| 
 | ||||
|     if (Archive::is_loading::value) { | ||||
|  |  | |||
|  | @ -97,11 +97,44 @@ union CoreVersion { | |||
|     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 { | ||||
| public: | ||||
|     explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, | ||||
|                           std::function<void()> prepare_reschedule_callback, u32 system_mode, | ||||
|                           u32 num_cores, u8 n3ds_mode); | ||||
|                           std::function<void()> prepare_reschedule_callback, MemoryMode memory_mode, | ||||
|                           u32 num_cores, const New3dsHwCapabilities& n3ds_hw_caps); | ||||
|     ~KernelSystem(); | ||||
| 
 | ||||
|     using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>; | ||||
|  | @ -279,6 +312,14 @@ public: | |||
| 
 | ||||
|     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
 | ||||
|     std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports; | ||||
| 
 | ||||
|  | @ -289,7 +330,7 @@ public: | |||
|     Core::Timing& timing; | ||||
| 
 | ||||
| private: | ||||
|     void MemoryInit(u32 mem_type, u8 n3ds_mode); | ||||
|     void MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode); | ||||
| 
 | ||||
|     std::function<void()> prepare_reschedule_callback; | ||||
| 
 | ||||
|  | @ -324,6 +365,9 @@ private: | |||
| 
 | ||||
|     u32 next_thread_id; | ||||
| 
 | ||||
|     MemoryMode memory_mode; | ||||
|     New3dsHwCapabilities n3ds_hw_caps; | ||||
| 
 | ||||
|     friend class boost::serialization::access; | ||||
|     template <class Archive> | ||||
|     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
 | ||||
| }; | ||||
| 
 | ||||
| namespace MemoryMode { | ||||
| enum N3DSMode : u8 { | ||||
|     Mode6 = 1, | ||||
|     Mode7 = 2, | ||||
|     Mode6_2 = 3, | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) { | ||||
|     ASSERT(mem_type != 1); | ||||
| 
 | ||||
| void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode) { | ||||
|     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 (n3ds_mode == MemoryMode::Mode6 || n3ds_mode == MemoryMode::Mode6_2) { | ||||
|             mem_type = 6; | ||||
|         if (n3ds_mode == New3dsMemoryMode::NewProd || n3ds_mode == New3dsMemoryMode::NewDev2) { | ||||
|             mem_type_index = 6; | ||||
|             reported_mem_type = 6; | ||||
|         } else if (n3ds_mode == MemoryMode::Mode7) { | ||||
|             mem_type = 7; | ||||
|         } else if (n3ds_mode == New3dsMemoryMode::NewDev1) { | ||||
|             mem_type_index = 7; | ||||
|             reported_mem_type = 7; | ||||
|         } else { | ||||
|             // 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.
 | ||||
|     VAddr base = 0; | ||||
|     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; | ||||
|     } | ||||
|  |  | |||
|  | @ -521,6 +521,11 @@ InstallStatus InstallFromNus(u64 title_id, int version) { | |||
| #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) { | ||||
|     u16 platform = static_cast<u16>(titleId >> 48); | ||||
|     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); | ||||
| 
 | ||||
| /**
 | ||||
|  * 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 | ||||
|  * @param titleId the installed title ID | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager) | |||
| namespace Service::APT { | ||||
| 
 | ||||
| /// 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 { | ||||
|     // There are two possible applet ids for each applet.
 | ||||
|  | @ -407,11 +407,56 @@ ResultCode AppletManager::Enable(AppletAttributes attributes) { | |||
|     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) { | ||||
|     auto slot = GetAppletSlotFromId(app_id); | ||||
|     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) { | ||||
|     auto slot = GetAppletSlotFromId(app_id); | ||||
|     if (slot != AppletSlot::Error) { | ||||
|  | @ -441,6 +486,15 @@ ResultCode AppletManager::SendNotification(Notification notification) { | |||
|             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) { | ||||
|     // The real APT service returns an error if there's a pending APT parameter when this function
 | ||||
|     // 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) { | ||||
|     // The real APT service returns an error if there's a pending APT parameter when this function
 | ||||
|     // is called.
 | ||||
|  | @ -963,10 +1082,7 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i | |||
|                           ErrorLevel::Status); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Basic heuristic to guess media type, needs proper implementation.
 | ||||
|     auto media_type = ((slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000 | ||||
|                           ? Service::FS::MediaType::SDMC | ||||
|                           : Service::FS::MediaType::NAND; | ||||
|     auto media_type = Service::AM::GetTitleMediaType(slot_data->title_id); | ||||
|     return AppletInfo{ | ||||
|         .title_id = slot_data->title_id, | ||||
|         .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, | ||||
|                                                      ApplicationJumpFlags flags) { | ||||
|     // 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.
 | ||||
|     auto application_slot_data = GetAppletSlot(AppletSlot::Application); | ||||
|     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 = | ||||
|         ((application_slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000 | ||||
|             ? Service::FS::MediaType::SDMC | ||||
|             : Service::FS::MediaType::NAND; | ||||
|         Service::AM::GetTitleMediaType(application_slot_data->title_id); | ||||
|     if (flags == ApplicationJumpFlags::UseCurrentParameters) { | ||||
|         app_jump_parameters.next_title_id = app_jump_parameters.current_title_id; | ||||
|         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; | ||||
|         */ | ||||
| 
 | ||||
|         auto new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type, | ||||
|                                                          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); | ||||
|         NS::RebootToTitle(system, app_jump_parameters.next_media_type, | ||||
|                           app_jump_parameters.next_title_id); | ||||
|         return RESULT_SUCCESS; | ||||
|     } | ||||
| } | ||||
|  | @ -1126,13 +1283,14 @@ ResultCode AppletManager::StartApplication(const std::vector<u8>& parameter, | |||
|     app_start_parameters.reset(); | ||||
| 
 | ||||
|     if (!paused) { | ||||
|         return WakeupApplication(); | ||||
|         return WakeupApplication(nullptr, {}); | ||||
|     } | ||||
| 
 | ||||
|     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.
 | ||||
|     // The real APT service does this by spin waiting on another thread until the application is
 | ||||
|     // registered.
 | ||||
|  | @ -1140,6 +1298,8 @@ ResultCode AppletManager::WakeupApplication() { | |||
|         .sender_id = AppletId::HomeMenu, | ||||
|         .destination_id = AppletId::Application, | ||||
|         .signal = SignalType::Wakeup, | ||||
|         .object = std::move(object), | ||||
|         .buffer = buffer, | ||||
|     }); | ||||
| 
 | ||||
|     return RESULT_SUCCESS; | ||||
|  | @ -1248,27 +1408,38 @@ void AppletManager::CaptureFrameBuffers() { | |||
| void AppletManager::LoadInputDevices() { | ||||
|     home_button = Input::CreateDevice<Input::ButtonDevice>( | ||||
|         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)) { | ||||
|         LoadInputDevices(); | ||||
|     } | ||||
| 
 | ||||
|     const bool state = home_button->GetStatus(); | ||||
|     // 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
 | ||||
|     // 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
 | ||||
|     // 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
 | ||||
|     Core::System::GetInstance().CoreTiming().ScheduleEvent( | ||||
|         usToCycles(home_button_update_interval_us) - cycles_late, home_button_update_event); | ||||
|     system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us) - cycles_late, | ||||
|                                       button_update_event); | ||||
| } | ||||
| 
 | ||||
| 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"); | ||||
|     } | ||||
|     HLE::Applets::Init(); | ||||
|     home_button_update_event = Core::System::GetInstance().CoreTiming().RegisterEvent( | ||||
|         "Home Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) { | ||||
|             HomeButtonUpdateEvent(user_data, cycles_late); | ||||
|     button_update_event = system.CoreTiming().RegisterEvent( | ||||
|         "APT Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) { | ||||
|             ButtonUpdateEvent(user_data, cycles_late); | ||||
|         }); | ||||
|     Core::System::GetInstance().CoreTiming().ScheduleEvent( | ||||
|         usToCycles(home_button_update_interval_us), home_button_update_event); | ||||
|     system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us), button_update_event); | ||||
| } | ||||
| 
 | ||||
| AppletManager::~AppletManager() { | ||||
|  |  | |||
|  | @ -99,6 +99,21 @@ enum class AppletId : u32 { | |||
|     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
 | ||||
| struct MessageParameter { | ||||
|     AppletId sender_id = AppletId::None; | ||||
|  | @ -256,10 +271,14 @@ public: | |||
|     ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes); | ||||
| 
 | ||||
|     ResultCode Enable(AppletAttributes attributes); | ||||
|     ResultCode Finalize(AppletId app_id); | ||||
|     u32 CountRegisteredApplet(); | ||||
|     bool IsRegistered(AppletId app_id); | ||||
|     ResultVal<AppletAttributes> GetAttribute(AppletId app_id); | ||||
| 
 | ||||
|     ResultVal<Notification> InquireNotification(AppletId app_id); | ||||
|     ResultCode SendNotification(Notification notification); | ||||
|     void SendNotificationToAll(Notification notification); | ||||
| 
 | ||||
|     ResultCode PrepareToStartLibraryApplet(AppletId applet_id); | ||||
|     ResultCode PreloadLibraryApplet(AppletId applet_id); | ||||
|  | @ -271,6 +290,9 @@ public: | |||
|                                   const std::vector<u8>& buffer); | ||||
|     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 StartSystemApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object, | ||||
|                                  const std::vector<u8>& buffer); | ||||
|  | @ -294,8 +316,10 @@ public: | |||
|                                           ApplicationJumpFlags flags); | ||||
|     ResultCode DoApplicationJump(const DeliverArg& arg); | ||||
| 
 | ||||
|     boost::optional<DeliverArg> ReceiveDeliverArg() const { | ||||
|         return deliver_arg; | ||||
|     boost::optional<DeliverArg> ReceiveDeliverArg() { | ||||
|         auto arg = deliver_arg; | ||||
|         deliver_arg = boost::none; | ||||
|         return arg; | ||||
|     } | ||||
|     void SetDeliverArg(boost::optional<DeliverArg> arg) { | ||||
|         deliver_arg = std::move(arg); | ||||
|  | @ -324,7 +348,8 @@ public: | |||
|     ResultCode PrepareToStartApplication(u64 title_id, FS::MediaType media_type); | ||||
|     ResultCode StartApplication(const std::vector<u8>& parameter, const std::vector<u8>& hmac, | ||||
|                                 bool paused); | ||||
|     ResultCode WakeupApplication(); | ||||
|     ResultCode WakeupApplication(std::shared_ptr<Kernel::Object> object, | ||||
|                                  const std::vector<u8>& buffer); | ||||
|     ResultCode CancelApplication(); | ||||
| 
 | ||||
|     struct AppletManInfo { | ||||
|  | @ -349,6 +374,10 @@ public: | |||
|         return app_jump_parameters; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<Service::FS::MediaType> Unknown54(u32 in_param); | ||||
|     TargetPlatform GetTargetPlatform(); | ||||
|     ApplicationRunningMode GetApplicationRunningMode(); | ||||
| 
 | ||||
| private: | ||||
|     /// APT lock retrieved via GetLockHandle.
 | ||||
|     std::shared_ptr<Kernel::Mutex> lock; | ||||
|  | @ -427,10 +456,16 @@ private: | |||
|     bool application_cancelled = false; | ||||
|     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::unique_ptr<Input::ButtonDevice> home_button; | ||||
|     std::unique_ptr<Input::ButtonDevice> power_button; | ||||
|     bool last_home_button_state = false; | ||||
|     bool last_power_button_state = false; | ||||
| 
 | ||||
|     Core::System& system; | ||||
| 
 | ||||
|  | @ -455,7 +490,7 @@ private: | |||
|     void CaptureFrameBuffers(); | ||||
| 
 | ||||
|     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> | ||||
|     void serialize(Archive& ar, const unsigned int file_version) { | ||||
|  | @ -474,6 +509,7 @@ private: | |||
|             ar& ordered_to_close_application; | ||||
|             ar& application_cancelled; | ||||
|             ar& application_close_target; | ||||
|             ar& new_3ds_mode_blocked; | ||||
|             ar& lock; | ||||
|             ar& capture_info; | ||||
|         } | ||||
|  |  | |||
|  | @ -16,16 +16,19 @@ | |||
| #include "core/hle/kernel/mutex.h" | ||||
| #include "core/hle/kernel/shared_memory.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/apt.h" | ||||
| #include "core/hle/service/apt/apt_a.h" | ||||
| #include "core/hle/service/apt/apt_s.h" | ||||
| #include "core/hle/service/apt/apt_u.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_s.h" | ||||
| #include "core/hle/service/cfg/cfg.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/service.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_relocated; | ||||
|     ar& cpu_percent; | ||||
|     ar& unknown_ns_state_field; | ||||
|     ar& screen_capture_post_permission; | ||||
|     ar& applet_manager; | ||||
|     if (file_version > 0) { | ||||
|  | @ -90,14 +92,19 @@ void Module::NSInterface::RebootSystem(Kernel::HLERequestContext& 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
 | ||||
|     // TODO: Utilize requested memory type.
 | ||||
|     const auto mem_type = rp.Pop<u8>(); | ||||
| 
 | ||||
|     LOG_WARNING(Service_APT, | ||||
|                 "called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}", | ||||
|                 launch_title, title_id, media_type, mem_type); | ||||
| 
 | ||||
|     // TODO: Implement loading a specific title.
 | ||||
|     apt->system.RequestReset(); | ||||
|     // TODO: Handle mem type.
 | ||||
|     if (launch_title) { | ||||
|         NS::RebootToTitle(apt->system, media_type, title_id); | ||||
|     } else { | ||||
|         apt->system.RequestReset(); | ||||
|     } | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|  | @ -371,6 +378,16 @@ void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) { | |||
|     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) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
|     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) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
|     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)); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
|     const auto param_size = rp.Pop<u32>(); | ||||
|  | @ -611,7 +670,7 @@ void Module::APTInterface::WakeupApplication(Kernel::HLERequestContext& ctx) { | |||
|     LOG_DEBUG(Service_APT, "called"); | ||||
| 
 | ||||
|     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) { | ||||
|  | @ -856,6 +915,28 @@ void Module::APTInterface::OrderToCloseSystemApplet(Kernel::HLERequestContext& c | |||
|     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) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
| 
 | ||||
|  | @ -972,29 +1053,124 @@ void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) { | |||
|     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); | ||||
|     auto in_param = rp.Pop<u32>(); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_APT, "called, screen_capture_post_permission={}", | ||||
|               apt->screen_capture_post_permission); | ||||
|     LOG_DEBUG(Service_APT, "called, in_param={}", in_param); | ||||
| 
 | ||||
|     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); | ||||
|     rb.Push(RESULT_SUCCESS); // No error
 | ||||
| } | ||||
| 
 | ||||
| void Module::APTInterface::GetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { | ||||
| void Module::APTInterface::GetScreenCapturePostPermission(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_APT, "(STUBBED) called, screen_capture_post_permission={}", | ||||
|               apt->screen_capture_post_permission); | ||||
|     LOG_DEBUG(Service_APT, "called"); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
|     rb.Push(RESULT_SUCCESS); // No error
 | ||||
|     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) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
|     const auto app_id = rp.PopEnum<AppletId>(); | ||||
|  | @ -1154,37 +1330,83 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) { | |||
|     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); | ||||
| 
 | ||||
|     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); | ||||
|     if (apt->unknown_ns_state_field) { | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(0); | ||||
|     } else { | ||||
|         PTM::CheckNew3DS(rb); | ||||
|     } | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.PushEnum(apt->applet_manager->GetTargetPlatform()); | ||||
| } | ||||
| 
 | ||||
| void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_APT, "called"); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
| 
 | ||||
|     LOG_WARNING(Service_APT, "(STUBBED) called"); | ||||
| 
 | ||||
|     PTM::CheckNew3DS(rb); | ||||
| } | ||||
| 
 | ||||
| void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) { | ||||
| void Module::APTInterface::GetApplicationRunningMode(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_APT, "called"); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
| 
 | ||||
|     LOG_WARNING(Service_APT, "(STUBBED) called"); | ||||
| 
 | ||||
|     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) { | ||||
|  |  | |||
|  | @ -214,6 +214,15 @@ public: | |||
|          */ | ||||
|         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. | ||||
|          *  Inputs: | ||||
|  | @ -241,6 +250,15 @@ public: | |||
|          */ | ||||
|         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 | ||||
|          * registered with NS yet. An AppID is "registered" once the process associated with the | ||||
|  | @ -257,6 +275,17 @@ public: | |||
|          */ | ||||
|         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); | ||||
| 
 | ||||
|         /**
 | ||||
|  | @ -596,6 +625,21 @@ public: | |||
|          */ | ||||
|         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 | ||||
|          *  Inputs: | ||||
|  | @ -687,6 +731,30 @@ public: | |||
|          */ | ||||
|         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 | ||||
|          *  Inputs: | ||||
|  | @ -818,27 +886,97 @@ public: | |||
|         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: | ||||
|          *      0 : Header Code[0x00550040] | ||||
|          *      1 : u8 The screenshot posting permission | ||||
|          *  Outputs: | ||||
|          *      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: | ||||
|          *      0 : Header Code[0x00560000] | ||||
|          *  Outputs: | ||||
|          *      1 : Result of function, 0 on success, otherwise error code | ||||
|          *      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: | ||||
|          *      1: Result code, 0 on success, otherwise error code | ||||
|          *      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 | ||||
|          *  when APT:PrepareToStartApplication is used with flags bit8 is set. | ||||
|          */ | ||||
|         void CheckNew3DSApp(Kernel::HLERequestContext& ctx); | ||||
|         void GetTargetPlatform(Kernel::HLERequestContext& ctx); | ||||
| 
 | ||||
|         /**
 | ||||
|          * Wrapper for PTMSYSM:CheckNew3DS | ||||
|  | @ -861,12 +999,20 @@ public: | |||
|         void CheckNew3DS(Kernel::HLERequestContext& ctx); | ||||
| 
 | ||||
|         /**
 | ||||
|          * APT::Unknown0x0103 service function. Determines whether Smash 4 allows C-Stick | ||||
|          * APT::GetApplicationRunningMode service function | ||||
|          *  Outputs: | ||||
|          *      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 | ||||
|  | @ -906,9 +1052,6 @@ private: | |||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     ScreencapPostPermission screen_capture_post_permission = | ||||
|  |  | |||
|  | @ -14,13 +14,13 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | |||
|         {0x0001, &APT_A::GetLockHandle, "GetLockHandle"}, | ||||
|         {0x0002, &APT_A::Initialize, "Initialize"}, | ||||
|         {0x0003, &APT_A::Enable, "Enable"}, | ||||
|         {0x0004, nullptr, "Finalize"}, | ||||
|         {0x0004, &APT_A::Finalize, "Finalize"}, | ||||
|         {0x0005, &APT_A::GetAppletManInfo, "GetAppletManInfo"}, | ||||
|         {0x0006, &APT_A::GetAppletInfo, "GetAppletInfo"}, | ||||
|         {0x0007, nullptr, "GetLastSignaledAppletId"}, | ||||
|         {0x0008, nullptr, "CountRegisteredApplet"}, | ||||
|         {0x0008, &APT_A::CountRegisteredApplet, "CountRegisteredApplet"}, | ||||
|         {0x0009, &APT_A::IsRegistered, "IsRegistered"}, | ||||
|         {0x000A, nullptr, "GetAttribute"}, | ||||
|         {0x000A, &APT_A::GetAttribute, "GetAttribute"}, | ||||
|         {0x000B, &APT_A::InquireNotification, "InquireNotification"}, | ||||
|         {0x000C, &APT_A::SendParameter, "SendParameter"}, | ||||
|         {0x000D, &APT_A::ReceiveParameter, "ReceiveParameter"}, | ||||
|  | @ -39,7 +39,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | |||
|         {0x001A, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, | ||||
|         {0x001B, &APT_A::StartApplication, "StartApplication"}, | ||||
|         {0x001C, &APT_A::WakeupApplication, "WakeupApplication"}, | ||||
|         {0x001D, nullptr, "CancelApplication"}, | ||||
|         {0x001D, &APT_A::CancelApplication, "CancelApplication"}, | ||||
|         {0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"}, | ||||
|         {0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"}, | ||||
|         {0x0020, nullptr, "StartNewestHomeMenu"}, | ||||
|  | @ -62,7 +62,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | |||
|         {0x0031, &APT_A::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, | ||||
|         {0x0032, &APT_A::DoApplicationJump, "DoApplicationJump"}, | ||||
|         {0x0033, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, | ||||
|         {0x0034, nullptr, "SendDeliverArg"}, | ||||
|         {0x0034, &APT_A::SendDeliverArg, "SendDeliverArg"}, | ||||
|         {0x0035, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"}, | ||||
|         {0x0036, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"}, | ||||
|         {0x0037, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"}, | ||||
|  | @ -70,8 +70,8 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | |||
|         {0x0039, nullptr, "PrepareToStartResidentApplet"}, | ||||
|         {0x003A, nullptr, "StartResidentApplet"}, | ||||
|         {0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"}, | ||||
|         {0x003C, nullptr, "SendDspSleep"}, | ||||
|         {0x003D, nullptr, "SendDspWakeUp"}, | ||||
|         {0x003C, &APT_A::SendDspSleep, "SendDspSleep"}, | ||||
|         {0x003D, &APT_A::SendDspWakeUp, "SendDspWakeUp"}, | ||||
|         {0x003E, nullptr, "ReplySleepQuery"}, | ||||
|         {0x003F, nullptr, "ReplySleepNotificationComplete"}, | ||||
|         {0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, | ||||
|  | @ -82,26 +82,27 @@ APT_A::APT_A(std::shared_ptr<Module> apt) | |||
|         {0x0045, &APT_A::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, | ||||
|         {0x0046, &APT_A::Wrap, "Wrap"}, | ||||
|         {0x0047, &APT_A::Unwrap, "Unwrap"}, | ||||
|         {0x0048, nullptr, "GetProgramInfo"}, | ||||
|         {0x0049, nullptr, "Reboot"}, | ||||
|         {0x0048, &APT_A::GetProgramInfo, "GetProgramInfo"}, | ||||
|         {0x0049, &APT_A::Reboot, "Reboot"}, | ||||
|         {0x004A, &APT_A::GetCaptureInfo, "GetCaptureInfo"}, | ||||
|         {0x004B, &APT_A::AppletUtility, "AppletUtility"}, | ||||
|         {0x004C, nullptr, "SetFatalErrDispMode"}, | ||||
|         {0x004D, nullptr, "GetAppletProgramInfo"}, | ||||
|         {0x004E, nullptr, "HardwareResetAsync"}, | ||||
|         {0x004E, &APT_A::HardwareResetAsync, "HardwareResetAsync"}, | ||||
|         {0x004F, &APT_A::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||||
|         {0x0050, &APT_A::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||||
|         {0x0051, &APT_A::GetStartupArgument, "GetStartupArgument"}, | ||||
|         {0x0052, nullptr, "Wrap1"}, | ||||
|         {0x0053, nullptr, "Unwrap1"}, | ||||
|         {0x0055, &APT_A::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, | ||||
|         {0x0056, &APT_A::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, | ||||
|         {0x0057, nullptr, "WakeupApplication2"}, | ||||
|         {0x0058, nullptr, "GetProgramID"}, | ||||
|         {0x0101, &APT_A::CheckNew3DSApp, "CheckNew3DSApp"}, | ||||
|         {0x0054, &APT_A::Unknown54, "Unknown54"}, | ||||
|         {0x0055, &APT_A::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"}, | ||||
|         {0x0056, &APT_A::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"}, | ||||
|         {0x0057, &APT_A::WakeupApplication2, "WakeupApplication2"}, | ||||
|         {0x0058, &APT_A::GetProgramId, "GetProgramId"}, | ||||
|         {0x0101, &APT_A::GetTargetPlatform, "GetTargetPlatform"}, | ||||
|         {0x0102, &APT_A::CheckNew3DS, "CheckNew3DS"}, | ||||
|         {0x0103, &APT_A::Unknown0x0103, "Unknown0x0103"}, | ||||
|         {0x0104, nullptr, "IsStandardMemoryLayout"}, | ||||
|         {0x0103, &APT_A::GetApplicationRunningMode, "GetApplicationRunningMode"}, | ||||
|         {0x0104, &APT_A::IsStandardMemoryLayout, "IsStandardMemoryLayout"}, | ||||
|         {0x0105, &APT_A::IsTitleAllowed, "IsTitleAllowed"}, | ||||
|         // clang-format on
 | ||||
|     }; | ||||
|  |  | |||
|  | @ -14,13 +14,13 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | |||
|         {0x0001, &APT_S::GetLockHandle, "GetLockHandle"}, | ||||
|         {0x0002, &APT_S::Initialize, "Initialize"}, | ||||
|         {0x0003, &APT_S::Enable, "Enable"}, | ||||
|         {0x0004, nullptr, "Finalize"}, | ||||
|         {0x0004, &APT_S::Finalize, "Finalize"}, | ||||
|         {0x0005, &APT_S::GetAppletManInfo, "GetAppletManInfo"}, | ||||
|         {0x0006, &APT_S::GetAppletInfo, "GetAppletInfo"}, | ||||
|         {0x0007, nullptr, "GetLastSignaledAppletId"}, | ||||
|         {0x0008, nullptr, "CountRegisteredApplet"}, | ||||
|         {0x0008, &APT_S::CountRegisteredApplet, "CountRegisteredApplet"}, | ||||
|         {0x0009, &APT_S::IsRegistered, "IsRegistered"}, | ||||
|         {0x000A, nullptr, "GetAttribute"}, | ||||
|         {0x000A, &APT_S::GetAttribute, "GetAttribute"}, | ||||
|         {0x000B, &APT_S::InquireNotification, "InquireNotification"}, | ||||
|         {0x000C, &APT_S::SendParameter, "SendParameter"}, | ||||
|         {0x000D, &APT_S::ReceiveParameter, "ReceiveParameter"}, | ||||
|  | @ -39,7 +39,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | |||
|         {0x001A, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, | ||||
|         {0x001B, &APT_S::StartApplication, "StartApplication"}, | ||||
|         {0x001C, &APT_S::WakeupApplication, "WakeupApplication"}, | ||||
|         {0x001D, nullptr, "CancelApplication"}, | ||||
|         {0x001D, &APT_S::CancelApplication, "CancelApplication"}, | ||||
|         {0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"}, | ||||
|         {0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"}, | ||||
|         {0x0020, nullptr, "StartNewestHomeMenu"}, | ||||
|  | @ -62,7 +62,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | |||
|         {0x0031, &APT_S::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, | ||||
|         {0x0032, &APT_S::DoApplicationJump, "DoApplicationJump"}, | ||||
|         {0x0033, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, | ||||
|         {0x0034, nullptr, "SendDeliverArg"}, | ||||
|         {0x0034, &APT_S::SendDeliverArg, "SendDeliverArg"}, | ||||
|         {0x0035, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"}, | ||||
|         {0x0036, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"}, | ||||
|         {0x0037, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"}, | ||||
|  | @ -70,8 +70,8 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | |||
|         {0x0039, nullptr, "PrepareToStartResidentApplet"}, | ||||
|         {0x003A, nullptr, "StartResidentApplet"}, | ||||
|         {0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"}, | ||||
|         {0x003C, nullptr, "SendDspSleep"}, | ||||
|         {0x003D, nullptr, "SendDspWakeUp"}, | ||||
|         {0x003C, &APT_S::SendDspSleep, "SendDspSleep"}, | ||||
|         {0x003D, &APT_S::SendDspWakeUp, "SendDspWakeUp"}, | ||||
|         {0x003E, nullptr, "ReplySleepQuery"}, | ||||
|         {0x003F, nullptr, "ReplySleepNotificationComplete"}, | ||||
|         {0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, | ||||
|  | @ -82,26 +82,27 @@ APT_S::APT_S(std::shared_ptr<Module> apt) | |||
|         {0x0045, &APT_S::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, | ||||
|         {0x0046, &APT_S::Wrap, "Wrap"}, | ||||
|         {0x0047, &APT_S::Unwrap, "Unwrap"}, | ||||
|         {0x0048, nullptr, "GetProgramInfo"}, | ||||
|         {0x0049, nullptr, "Reboot"}, | ||||
|         {0x0048, &APT_S::GetProgramInfo, "GetProgramInfo"}, | ||||
|         {0x0049, &APT_S::Reboot, "Reboot"}, | ||||
|         {0x004A, &APT_S::GetCaptureInfo, "GetCaptureInfo"}, | ||||
|         {0x004B, &APT_S::AppletUtility, "AppletUtility"}, | ||||
|         {0x004C, nullptr, "SetFatalErrDispMode"}, | ||||
|         {0x004D, nullptr, "GetAppletProgramInfo"}, | ||||
|         {0x004E, nullptr, "HardwareResetAsync"}, | ||||
|         {0x004E, &APT_S::HardwareResetAsync, "HardwareResetAsync"}, | ||||
|         {0x004F, &APT_S::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||||
|         {0x0050, &APT_S::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||||
|         {0x0051, &APT_S::GetStartupArgument, "GetStartupArgument"}, | ||||
|         {0x0052, nullptr, "Wrap1"}, | ||||
|         {0x0053, nullptr, "Unwrap1"}, | ||||
|         {0x0055, &APT_S::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, | ||||
|         {0x0056, &APT_S::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, | ||||
|         {0x0057, nullptr, "WakeupApplication2"}, | ||||
|         {0x0058, nullptr, "GetProgramID"}, | ||||
|         {0x0101, &APT_S::CheckNew3DSApp, "CheckNew3DSApp"}, | ||||
|         {0x0054, &APT_S::Unknown54, "Unknown54"}, | ||||
|         {0x0055, &APT_S::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"}, | ||||
|         {0x0056, &APT_S::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"}, | ||||
|         {0x0057, &APT_S::WakeupApplication2, "WakeupApplication2"}, | ||||
|         {0x0058, &APT_S::GetProgramId, "GetProgramId"}, | ||||
|         {0x0101, &APT_S::GetTargetPlatform, "GetTargetPlatform"}, | ||||
|         {0x0102, &APT_S::CheckNew3DS, "CheckNew3DS"}, | ||||
|         {0x0103, &APT_S::Unknown0x0103, "Unknown0x0103"}, | ||||
|         {0x0104, nullptr, "IsStandardMemoryLayout"}, | ||||
|         {0x0103, &APT_S::GetApplicationRunningMode, "GetApplicationRunningMode"}, | ||||
|         {0x0104, &APT_S::IsStandardMemoryLayout, "IsStandardMemoryLayout"}, | ||||
|         {0x0105, &APT_S::IsTitleAllowed, "IsTitleAllowed"}, | ||||
|         // clang-format on
 | ||||
|     }; | ||||
|  |  | |||
|  | @ -14,13 +14,13 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | |||
|         {0x0001, &APT_U::GetLockHandle, "GetLockHandle"}, | ||||
|         {0x0002, &APT_U::Initialize, "Initialize"}, | ||||
|         {0x0003, &APT_U::Enable, "Enable"}, | ||||
|         {0x0004, nullptr, "Finalize"}, | ||||
|         {0x0004, &APT_U::Finalize, "Finalize"}, | ||||
|         {0x0005, &APT_U::GetAppletManInfo, "GetAppletManInfo"}, | ||||
|         {0x0006, &APT_U::GetAppletInfo, "GetAppletInfo"}, | ||||
|         {0x0007, nullptr, "GetLastSignaledAppletId"}, | ||||
|         {0x0008, nullptr, "CountRegisteredApplet"}, | ||||
|         {0x0008, &APT_U::CountRegisteredApplet, "CountRegisteredApplet"}, | ||||
|         {0x0009, &APT_U::IsRegistered, "IsRegistered"}, | ||||
|         {0x000A, nullptr, "GetAttribute"}, | ||||
|         {0x000A, &APT_U::GetAttribute, "GetAttribute"}, | ||||
|         {0x000B, &APT_U::InquireNotification, "InquireNotification"}, | ||||
|         {0x000C, &APT_U::SendParameter, "SendParameter"}, | ||||
|         {0x000D, &APT_U::ReceiveParameter, "ReceiveParameter"}, | ||||
|  | @ -39,7 +39,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | |||
|         {0x001A, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, | ||||
|         {0x001B, &APT_U::StartApplication, "StartApplication"}, | ||||
|         {0x001C, &APT_U::WakeupApplication, "WakeupApplication"}, | ||||
|         {0x001D, nullptr, "CancelApplication"}, | ||||
|         {0x001D, &APT_U::CancelApplication, "CancelApplication"}, | ||||
|         {0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"}, | ||||
|         {0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"}, | ||||
|         {0x0020, nullptr, "StartNewestHomeMenu"}, | ||||
|  | @ -62,7 +62,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | |||
|         {0x0031, &APT_U::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, | ||||
|         {0x0032, &APT_U::DoApplicationJump, "DoApplicationJump"}, | ||||
|         {0x0033, &APT_U::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, | ||||
|         {0x0034, nullptr, "SendDeliverArg"}, | ||||
|         {0x0034, &APT_U::SendDeliverArg, "SendDeliverArg"}, | ||||
|         {0x0035, &APT_U::ReceiveDeliverArg, "ReceiveDeliverArg"}, | ||||
|         {0x0036, &APT_U::LoadSysMenuArg, "LoadSysMenuArg"}, | ||||
|         {0x0037, &APT_U::StoreSysMenuArg, "StoreSysMenuArg"}, | ||||
|  | @ -70,8 +70,8 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | |||
|         {0x0039, nullptr, "PrepareToStartResidentApplet"}, | ||||
|         {0x003A, nullptr, "StartResidentApplet"}, | ||||
|         {0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"}, | ||||
|         {0x003C, nullptr, "SendDspSleep"}, | ||||
|         {0x003D, nullptr, "SendDspWakeUp"}, | ||||
|         {0x003C, &APT_U::SendDspSleep, "SendDspSleep"}, | ||||
|         {0x003D, &APT_U::SendDspWakeUp, "SendDspWakeUp"}, | ||||
|         {0x003E, nullptr, "ReplySleepQuery"}, | ||||
|         {0x003F, nullptr, "ReplySleepNotificationComplete"}, | ||||
|         {0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, | ||||
|  | @ -82,26 +82,27 @@ APT_U::APT_U(std::shared_ptr<Module> apt) | |||
|         {0x0045, &APT_U::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, | ||||
|         {0x0046, &APT_U::Wrap, "Wrap"}, | ||||
|         {0x0047, &APT_U::Unwrap, "Unwrap"}, | ||||
|         {0x0048, nullptr, "GetProgramInfo"}, | ||||
|         {0x0049, nullptr, "Reboot"}, | ||||
|         {0x0048, &APT_U::GetProgramInfo, "GetProgramInfo"}, | ||||
|         {0x0049, &APT_U::Reboot, "Reboot"}, | ||||
|         {0x004A, &APT_U::GetCaptureInfo, "GetCaptureInfo"}, | ||||
|         {0x004B, &APT_U::AppletUtility, "AppletUtility"}, | ||||
|         {0x004C, nullptr, "SetFatalErrDispMode"}, | ||||
|         {0x004D, nullptr, "GetAppletProgramInfo"}, | ||||
|         {0x004E, nullptr, "HardwareResetAsync"}, | ||||
|         {0x004E, &APT_U::HardwareResetAsync, "HardwareResetAsync"}, | ||||
|         {0x004F, &APT_U::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||||
|         {0x0050, &APT_U::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||||
|         {0x0051, &APT_U::GetStartupArgument, "GetStartupArgument"}, | ||||
|         {0x0052, nullptr, "Wrap1"}, | ||||
|         {0x0053, nullptr, "Unwrap1"}, | ||||
|         {0x0055, &APT_U::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, | ||||
|         {0x0056, &APT_U::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, | ||||
|         {0x0057, nullptr, "WakeupApplication2"}, | ||||
|         {0x0058, nullptr, "GetProgramID"}, | ||||
|         {0x0101, &APT_U::CheckNew3DSApp, "CheckNew3DSApp"}, | ||||
|         {0x0054, &APT_U::Unknown54, "Unknown54"}, | ||||
|         {0x0055, &APT_U::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"}, | ||||
|         {0x0056, &APT_U::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"}, | ||||
|         {0x0057, &APT_U::WakeupApplication2, "WakeupApplication2"}, | ||||
|         {0x0058, &APT_U::GetProgramId, "GetProgramId"}, | ||||
|         {0x0101, &APT_U::GetTargetPlatform, "GetTargetPlatform"}, | ||||
|         {0x0102, &APT_U::CheckNew3DS, "CheckNew3DS"}, | ||||
|         {0x0103, &APT_U::Unknown0x0103, "Unknown0x0103"}, | ||||
|         {0x0104, nullptr, "IsStandardMemoryLayout"}, | ||||
|         {0x0103, &APT_U::GetApplicationRunningMode, "GetApplicationRunningMode"}, | ||||
|         {0x0104, &APT_U::IsStandardMemoryLayout, "IsStandardMemoryLayout"}, | ||||
|         {0x0105, &APT_U::IsTitleAllowed, "IsTitleAllowed"}, | ||||
|         // clang-format on
 | ||||
|     }; | ||||
|  |  | |||
|  | @ -8,5 +8,6 @@ namespace Service::APT::ErrCodes { | |||
| enum { | ||||
|     ParameterPresent = 2, | ||||
|     InvalidAppletSlot = 4, | ||||
|     AppNotRunning = 11, | ||||
| }; | ||||
| } // namespace Service::APT::ErrCodes
 | ||||
|  |  | |||
|  | @ -29,4 +29,17 @@ std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title | |||
|     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
 | ||||
|  |  | |||
|  | @ -18,4 +18,7 @@ namespace Service::NS { | |||
| /// 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); | ||||
| 
 | ||||
| /// Reboots the system to the specified title.
 | ||||
| void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id); | ||||
| 
 | ||||
| } // namespace Service::NS
 | ||||
|  |  | |||
|  | @ -672,30 +672,23 @@ void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) { | |||
| 
 | ||||
| void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx); | ||||
| 
 | ||||
|     u32 process_id = rp.Pop<u32>(); | ||||
|     const auto process_id = rp.Pop<u32>(); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_FS, "process_id={}", process_id); | ||||
| 
 | ||||
|     auto program_info = program_info_map.find(process_id); | ||||
| 
 | ||||
|     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
 | ||||
|         // remains the same.
 | ||||
|         rb.Push(ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS, | ||||
|                            ErrorSummary::NotFound, ErrorLevel::Status)); | ||||
|         rb.Push(program_info_result.Code()); | ||||
|         rb.Skip(4, false); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.Push(program_info->second.program_id); | ||||
|     rb.Push(static_cast<u8>(program_info->second.media_type)); | ||||
| 
 | ||||
|     // TODO(Subv): Find out what this value means.
 | ||||
|     rb.Push<u32>(0); | ||||
|     rb.PushRaw(program_info_result.Unwrap()); | ||||
| } | ||||
| 
 | ||||
| void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) { | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <unordered_map> | ||||
| #include <boost/serialization/base_object.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "core/file_sys/errors.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Core { | ||||
|  | @ -17,6 +18,13 @@ namespace Service::FS { | |||
| 
 | ||||
| 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 { | ||||
|     // 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
 | ||||
|  | @ -45,6 +53,17 @@ public: | |||
| 
 | ||||
|     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: | ||||
|     void Initialize(Kernel::HLERequestContext& ctx); | ||||
| 
 | ||||
|  | @ -602,11 +621,6 @@ private: | |||
|     static ResultVal<u16> GetSpecialContentIndexFromTMD(MediaType media_type, u64 title_id, | ||||
|                                                         SpecialContentType type); | ||||
| 
 | ||||
|     struct ProgramInfo { | ||||
|         u64 program_id; | ||||
|         MediaType media_type; | ||||
|     }; | ||||
| 
 | ||||
|     std::unordered_map<u32, ProgramInfo> program_info_map; | ||||
|     std::string current_gamecard_path; | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ | |||
| #include "common/common_types.h" | ||||
| #include "common/file_util.h" | ||||
| #include "core/file_sys/romfs_reader.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
|  | @ -99,23 +100,36 @@ public: | |||
|     virtual ResultStatus Load(std::shared_ptr<Kernel::Process>& process) = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Loads the system mode that this application needs. | ||||
|      * This function defaults to 2 (96MB allocated to the application) if it can't read the | ||||
|      * Loads the core version (FIRM title ID low) that this application needs. | ||||
|      * This function defaults to 0x2 (NATIVE_FIRM) if it can't read the | ||||
|      * 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() { | ||||
|         // 96MB allocated to the application.
 | ||||
|         return std::make_pair(2, ResultStatus::Success); | ||||
|     virtual std::pair<std::optional<u32>, ResultStatus> LoadCoreVersion() { | ||||
|         return std::make_pair(0x2, ResultStatus::Success); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Loads the N3ds mode that this application uses. | ||||
|      * It defaults to 0 (O3DS default) if it can't read the information. | ||||
|      * @returns A pair with the optional N3ds mode, and the status. | ||||
|      * Loads the memory mode that this application needs. | ||||
|      * This function defaults to Dev1 (96MB allocated to the application) if it can't read the | ||||
|      * information. | ||||
|      * @returns A pair with the optional memory mode, and the status. | ||||
|      */ | ||||
|     virtual std::pair<std::optional<u8>, ResultStatus> LoadKernelN3dsMode() { | ||||
|         return std::make_pair(u8(0), ResultStatus::Success); | ||||
|     virtual std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> LoadKernelMemoryMode() { | ||||
|         // 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/file_sys/ncch_container.h" | ||||
| #include "core/file_sys/title_metadata.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/service/am/am.h" | ||||
|  | @ -47,7 +48,7 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) { | |||
|     return FileType::Error; | ||||
| } | ||||
| 
 | ||||
| std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() { | ||||
| std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadCoreVersion() { | ||||
|     if (!is_loaded) { | ||||
|         ResultStatus res = base_ncch.Load(); | ||||
|         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.
 | ||||
|     return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.system_mode.Value(), | ||||
|                           ResultStatus::Success); | ||||
|     // Provide the core version from the exheader.
 | ||||
|     auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps; | ||||
|     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) { | ||||
|         ResultStatus res = base_ncch.Load(); | ||||
|         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.
 | ||||
|     return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.n3ds_mode, | ||||
|                           ResultStatus::Success); | ||||
|     // Provide the memory mode from the exheader.
 | ||||
|     auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps; | ||||
|     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) { | ||||
|  |  | |||
|  | @ -32,13 +32,16 @@ public: | |||
| 
 | ||||
|     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. | ||||
|      * @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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,7 +18,8 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) | |||
|     timing = std::make_unique<Core::Timing>(1, 100); | ||||
|     memory = std::make_unique<Memory::MemorySystem>(); | ||||
|     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))); | ||||
|     page_table = kernel->GetCurrentProcess()->vm_manager.page_table; | ||||
|  |  | |||
|  | @ -25,7 +25,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|     Core::Timing timing(1, 100); | ||||
|     Memory::MemorySystem memory; | ||||
|     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(); | ||||
|     HLERequestContext context(kernel, std::move(server), nullptr); | ||||
| 
 | ||||
|  | @ -248,7 +249,8 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | |||
|     Core::Timing timing(1, 100); | ||||
|     Memory::MemorySystem memory; | ||||
|     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(); | ||||
|     HLERequestContext context(kernel, std::move(server), nullptr); | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,7 +11,8 @@ TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") { | |||
|     Core::Timing timing(1, 100); | ||||
|     Memory::MemorySystem memory; | ||||
|     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") { | ||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||
|         CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); | ||||
|  |  | |||
|  | @ -17,7 +17,8 @@ TEST_CASE("Memory Basics", "[kernel][memory]") { | |||
|     Core::Timing timing(1, 100); | ||||
|     Memory::MemorySystem memory; | ||||
|     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); | ||||
|     SECTION("mapping memory") { | ||||
|         // 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