Kernel/Loader: Grab the system mode from the NCCH ExHeader.
3dsx and elf files default to system mode 2 (96MB allocated to the application). This allows Home Menu to boot without modifications. Closes #1849
This commit is contained in:
		| @@ -129,16 +129,23 @@ int main(int argc, char** argv) { | ||||
|  | ||||
|     std::unique_ptr<EmuWindow_SDL2> emu_window = std::make_unique<EmuWindow_SDL2>(); | ||||
|  | ||||
|     System::Init(emu_window.get()); | ||||
|     SCOPE_EXIT({ System::Shutdown(); }); | ||||
|  | ||||
|     std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(boot_filename); | ||||
|     if (!loader) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", boot_filename.c_str()); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     Loader::ResultStatus load_result = loader->Load(); | ||||
|     u32 system_mode; | ||||
|     Loader::ResultStatus load_result = loader->LoadKernelSystemMode(system_mode); | ||||
|     if (Loader::ResultStatus::Success != load_result) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM (Error %i)!", load_result); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     System::Init(emu_window.get(), system_mode); | ||||
|     SCOPE_EXIT({ System::Shutdown(); }); | ||||
|  | ||||
|     load_result = loader->Load(); | ||||
|     if (Loader::ResultStatus::Success != load_result) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM (Error %i)!", load_result); | ||||
|         return -1; | ||||
|   | ||||
| @@ -253,7 +253,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool GMainWindow::InitializeSystem() { | ||||
| bool GMainWindow::InitializeSystem(u32 system_mode) { | ||||
|     // Shutdown previous session if the emu thread is still active... | ||||
|     if (emu_thread != nullptr) | ||||
|         ShutdownGame(); | ||||
| @@ -270,7 +270,7 @@ bool GMainWindow::InitializeSystem() { | ||||
|     } | ||||
|  | ||||
|     // Initialize the core emulation | ||||
|     System::Result system_result = System::Init(render_window); | ||||
|     System::Result system_result = System::Init(render_window, system_mode); | ||||
|     if (System::Result::Success != system_result) { | ||||
|         switch (system_result) { | ||||
|         case System::Result::ErrorInitVideoCore: | ||||
| @@ -299,8 +299,21 @@ bool GMainWindow::LoadROM(const std::string& filename) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     u32 system_mode; | ||||
|     Loader::ResultStatus load_result = app_loader->LoadKernelSystemMode(system_mode); | ||||
|     if (Loader::ResultStatus::Success != load_result) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM!", load_result); | ||||
|         QMessageBox::critical(this, tr("Error while loading ROM!"), | ||||
|                               tr("Could not determine the system mode.")); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if (!InitializeSystem(system_mode)) | ||||
|         return false; | ||||
|  | ||||
|     Loader::ResultStatus result = app_loader->Load(); | ||||
|     if (Loader::ResultStatus::Success != result) { | ||||
|         System::Shutdown(); | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM!"); | ||||
|  | ||||
|         switch (result) { | ||||
| @@ -338,14 +351,9 @@ void GMainWindow::BootGame(const std::string& filename) { | ||||
|     LOG_INFO(Frontend, "Citra starting..."); | ||||
|     StoreRecentFile(filename); // Put the filename on top of the list | ||||
|  | ||||
|     if (!InitializeSystem()) | ||||
|     if (!LoadROM(filename)) | ||||
|         return; | ||||
|  | ||||
|     if (!LoadROM(filename)) { | ||||
|         System::Shutdown(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Create and start the emulation thread | ||||
|     emu_thread = std::make_unique<EmuThread>(render_window); | ||||
|     emit EmulationStarting(emu_thread.get()); | ||||
|   | ||||
| @@ -60,7 +60,12 @@ signals: | ||||
|     void EmulationStopping(); | ||||
|  | ||||
| private: | ||||
|     bool InitializeSystem(); | ||||
|     /** | ||||
|      * Initializes the emulation system. | ||||
|      * @param system_mode The system mode with which to intialize the kernel. | ||||
|      * @returns Whether the system was properly initialized. | ||||
|      */ | ||||
|     bool InitializeSystem(u32 system_mode); | ||||
|     bool LoadROM(const std::string& filename); | ||||
|     void BootGame(const std::string& filename); | ||||
|     void ShutdownGame(); | ||||
|   | ||||
| @@ -124,13 +124,11 @@ void HandleTable::Clear() { | ||||
| } | ||||
|  | ||||
| /// Initialize the kernel | ||||
| void Init() { | ||||
| void Init(u32 system_mode) { | ||||
|     ConfigMem::Init(); | ||||
|     SharedPage::Init(); | ||||
|  | ||||
|     // TODO(yuriks): The memory type parameter needs to be determined by the ExHeader field instead | ||||
|     // For now it defaults to the one with a largest allocation to the app | ||||
|     Kernel::MemoryInit(2); // Allocates 96MB to the application | ||||
|     Kernel::MemoryInit(system_mode); | ||||
|  | ||||
|     Kernel::ResourceLimitsInit(); | ||||
|     Kernel::ThreadingInit(); | ||||
|   | ||||
| @@ -286,8 +286,8 @@ private: | ||||
|  | ||||
| extern HandleTable g_handle_table; | ||||
|  | ||||
| /// Initialize the kernel | ||||
| void Init(); | ||||
| /// Initialize the kernel with the specified system mode. | ||||
| void Init(u32 system_mode); | ||||
|  | ||||
| /// Shutdown the kernel | ||||
| void Shutdown(); | ||||
|   | ||||
| @@ -95,6 +95,17 @@ public: | ||||
|      */ | ||||
|     virtual ResultStatus Load() = 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 information. | ||||
|      * @param system_mode Out variable where the system mode will be stored. | ||||
|      * @returns ResultStatus result of the operation | ||||
|      */ | ||||
|     virtual ResultStatus LoadKernelSystemMode(u32& system_mode) { | ||||
|         system_mode = 2; // 96MB allocated to the application. | ||||
|         return ResultStatus::Success; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the code (typically .code section) of the application | ||||
|      * @param buffer Reference to buffer to store data | ||||
|   | ||||
| @@ -117,6 +117,14 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) { | ||||
|     return FileType::Error; | ||||
| } | ||||
|  | ||||
| ResultStatus AppLoader_NCCH::LoadKernelSystemMode(u32& memory_type) { | ||||
|     ResultStatus result = LoadExeFS(); | ||||
|     if (result != ResultStatus::Success) | ||||
|         return result; | ||||
|     memory_type = exheader_header.arm11_system_local_caps.system_mode; | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
|  | ||||
| ResultStatus AppLoader_NCCH::LoadExec() { | ||||
|     using Kernel::SharedPtr; | ||||
|     using Kernel::CodeSet; | ||||
| @@ -277,6 +285,7 @@ ResultStatus AppLoader_NCCH::LoadExeFS() { | ||||
|     LOG_DEBUG(Loader, "Core version:                %d", core_version); | ||||
|     LOG_DEBUG(Loader, "Thread priority:             0x%X", priority); | ||||
|     LOG_DEBUG(Loader, "Resource limit category:     %d", resource_limit_category); | ||||
|     LOG_DEBUG(Loader, "System Mode:                 %d", exheader_header.arm11_system_local_caps.system_mode); | ||||
|  | ||||
|     if (exheader_header.arm11_system_local_caps.program_id != ncch_header.program_id) { | ||||
|         LOG_ERROR(Loader, "ExHeader Program ID mismatch: the ROM is probably encrypted."); | ||||
|   | ||||
| @@ -185,6 +185,13 @@ public: | ||||
|      */ | ||||
|     ResultStatus Load() override; | ||||
|  | ||||
|     /** | ||||
|      * Loads the Exheader and returns the system mode for this application. | ||||
|      * @param system_mode Out variable where the system mode will be stored. | ||||
|      * @return ResultStatus result of the operation | ||||
|      */ | ||||
|     ResultStatus LoadKernelSystemMode(u32& system_mode); | ||||
|  | ||||
|     /** | ||||
|      * Get the code (typically .code section) of the application | ||||
|      * @param buffer Reference to buffer to store data | ||||
|   | ||||
| @@ -17,12 +17,12 @@ namespace System { | ||||
|  | ||||
| static bool is_powered_on{false}; | ||||
|  | ||||
| Result Init(EmuWindow* emu_window) { | ||||
| Result Init(EmuWindow* emu_window, u32 system_mode) { | ||||
|     Core::Init(); | ||||
|     CoreTiming::Init(); | ||||
|     Memory::Init(); | ||||
|     HW::Init(); | ||||
|     Kernel::Init(); | ||||
|     Kernel::Init(system_mode); | ||||
|     HLE::Init(); | ||||
|     if (!VideoCore::Init(emu_window)) { | ||||
|         return Result::ErrorInitVideoCore; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ enum class Result { | ||||
|     ErrorInitVideoCore, ///< Something went wrong during video core init | ||||
| }; | ||||
|  | ||||
| Result Init(EmuWindow* emu_window); | ||||
| Result Init(EmuWindow* emu_window, u32 system_mode); | ||||
| bool IsPoweredOn(); | ||||
| void Shutdown(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Subv
					Subv