core: Detect and return error if GBA virtual console is loaded. (#6257)
This commit is contained in:
parent
d704c6a3ac
commit
84e54a52a6
6 changed files with 33 additions and 6 deletions
|
@ -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"),
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -84,6 +84,8 @@ public:
|
||||||
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
|
||||||
|
ErrorLoader_ErrorGbaTitle, ///< Error loading the specified application as it is GBA Virtual
|
||||||
|
///< Console
|
||||||
ErrorSystemFiles, ///< Error in finding system files
|
ErrorSystemFiles, ///< Error in finding system files
|
||||||
ErrorVideoCore, ///< Error in the video core
|
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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue