core: Detect and return error if GBA virtual console is loaded. (#6257)

This commit is contained in:
Steveice10 2023-01-23 01:51:57 -08:00 committed by GitHub
parent d704c6a3ac
commit 84e54a52a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 33 additions and 6 deletions

View File

@ -1015,6 +1015,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
"titles</a>.")); "titles</a>."));
break; break;
case Core::System::ResultStatus::ErrorLoader_ErrorGbaTitle:
QMessageBox::critical(this, tr("Unsupported ROM"),
tr("GBA Virtual Console ROMs are not supported by Citra."));
break;
case Core::System::ResultStatus::ErrorVideoCore: case Core::System::ResultStatus::ErrorVideoCore:
QMessageBox::critical( QMessageBox::critical(
this, tr("Video Core Error"), this, tr("Video Core Error"),

View File

@ -268,6 +268,8 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
return ResultStatus::ErrorLoader_ErrorEncrypted; return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat: case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat; return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorGbaTitle:
return ResultStatus::ErrorLoader_ErrorGbaTitle;
default: default:
return ResultStatus::ErrorSystemMode; return ResultStatus::ErrorSystemMode;
} }
@ -292,7 +294,6 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
telemetry_session->AddInitialInfo(*app_loader); telemetry_session->AddInitialInfo(*app_loader);
std::shared_ptr<Kernel::Process> process; std::shared_ptr<Kernel::Process> process;
const Loader::ResultStatus load_result{app_loader->Load(process)}; const Loader::ResultStatus load_result{app_loader->Load(process)};
kernel->SetCurrentProcess(process);
if (Loader::ResultStatus::Success != load_result) { if (Loader::ResultStatus::Success != load_result) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
System::Shutdown(); System::Shutdown();
@ -302,10 +303,13 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
return ResultStatus::ErrorLoader_ErrorEncrypted; return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat: case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat; return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorGbaTitle:
return ResultStatus::ErrorLoader_ErrorGbaTitle;
default: default:
return ResultStatus::ErrorLoader; return ResultStatus::ErrorLoader;
} }
} }
kernel->SetCurrentProcess(process);
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this); cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
title_id = 0; title_id = 0;
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
@ -539,7 +543,8 @@ void System::Shutdown(bool is_deserializing) {
perf_results.emulation_speed * 100.0); perf_results.emulation_speed * 100.0);
telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps); telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0); telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0);
telemetry_session->AddField(performance, "Mean_Frametime_MS", perf_stats->GetMeanFrametime()); telemetry_session->AddField(performance, "Mean_Frametime_MS",
perf_stats ? perf_stats->GetMeanFrametime() : 0);
// Shutdown emulation session // Shutdown emulation session
VideoCore::Shutdown(); VideoCore::Shutdown();

View File

@ -82,10 +82,12 @@ public:
ErrorSystemMode, ///< Error determining the system mode ErrorSystemMode, ///< Error determining the system mode
ErrorLoader, ///< Error loading the specified application ErrorLoader, ///< Error loading the specified application
ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
/// invalid format /// invalid format
ErrorSystemFiles, ///< Error in finding system files ErrorLoader_ErrorGbaTitle, ///< Error loading the specified application as it is GBA Virtual
ErrorVideoCore, ///< Error in the video core ///< Console
ErrorSystemFiles, ///< Error in finding system files
ErrorVideoCore, ///< Error in the video core
ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having
/// generic drivers installed /// generic drivers installed
ErrorVideoCore_ErrorBelowGL43, ///< Error in the video core due to the user not having ErrorVideoCore_ErrorBelowGL43, ///< Error in the video core due to the user not having

View File

@ -75,6 +75,7 @@ enum class ResultStatus {
ErrorAlreadyLoaded, ErrorAlreadyLoaded,
ErrorMemoryAllocationFailed, ErrorMemoryAllocationFailed,
ErrorEncrypted, ErrorEncrypted,
ErrorGbaTitle,
}; };
constexpr u32 MakeMagic(char a, char b, char c, char d) { constexpr u32 MakeMagic(char a, char b, char c, char d) {

View File

@ -85,6 +85,11 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
u64_le program_id; u64_le program_id;
if (ResultStatus::Success == ReadCode(code) && if (ResultStatus::Success == ReadCode(code) &&
ResultStatus::Success == ReadProgramId(program_id)) { ResultStatus::Success == ReadProgramId(program_id)) {
if (IsGbaVirtualConsole(code)) {
LOG_ERROR(Loader, "Encountered unsupported GBA Virtual Console code section.");
return ResultStatus::ErrorGbaTitle;
}
std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
(const char*)overlay_ncch->exheader_header.codeset_info.name, 8); (const char*)overlay_ncch->exheader_header.codeset_info.name, 8);
@ -177,6 +182,12 @@ void AppLoader_NCCH::ParseRegionLockoutInfo() {
} }
} }
bool AppLoader_NCCH::IsGbaVirtualConsole(const std::vector<u8>& code) {
const u32* gbaVcHeader = reinterpret_cast<const u32*>(code.data() + code.size() - 0x10);
return code.size() >= 0x10 && gbaVcHeader[0] == MakeMagic('.', 'C', 'A', 'A') &&
gbaVcHeader[1] == 1;
}
ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) { ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
u64_le ncch_program_id; u64_le ncch_program_id;

View File

@ -78,6 +78,9 @@ private:
/// Reads the region lockout info in the SMDH and send it to CFG service /// Reads the region lockout info in the SMDH and send it to CFG service
void ParseRegionLockoutInfo(); void ParseRegionLockoutInfo();
/// Detects whether the NCCH contains GBA Virtual Console.
bool IsGbaVirtualConsole(const std::vector<u8>& code);
FileSys::NCCHContainer base_ncch; FileSys::NCCHContainer base_ncch;
FileSys::NCCHContainer update_ncch; FileSys::NCCHContainer update_ncch;
FileSys::NCCHContainer* overlay_ncch; FileSys::NCCHContainer* overlay_ncch;