core: Fix memory mode handling and n3ds exclusive app detection (#1560)

This commit is contained in:
PabloMK7
2026-01-02 15:03:23 +01:00
committed by GitHub
parent 43e044ad9a
commit 4ac18f5e18
10 changed files with 64 additions and 19 deletions
+1 -1
View File
@@ -222,7 +222,7 @@ jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsVisibleSystemTitle(JNIEnv
return false; return false;
} }
return smdh->flags & Loader::SMDH::Flags::Visible; return smdh->flags.visible;
} }
jstring Java_org_citra_citra_1emu_model_GameInfo_getFileType(JNIEnv* env, jobject obj) { jstring Java_org_citra_citra_1emu_model_GameInfo_getFileType(JNIEnv* env, jobject obj) {
+1 -1
View File
@@ -92,7 +92,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
if (Loader::IsValidSMDH(smdh)) { if (Loader::IsValidSMDH(smdh)) {
if (system_title) { if (system_title) {
auto smdh_struct = reinterpret_cast<Loader::SMDH*>(smdh.data()); auto smdh_struct = reinterpret_cast<Loader::SMDH*>(smdh.data());
if (!(smdh_struct->flags & Loader::SMDH::Flags::Visible)) { if (!smdh_struct->flags.visible) {
// Skip system titles without the visible flag. // Skip system titles without the visible flag.
return true; return true;
} }
+5 -11
View File
@@ -362,8 +362,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
ASSERT(n3ds_hw_caps.first); ASSERT(n3ds_hw_caps.first);
app_n3ds_hw_capabilities = n3ds_hw_caps.first.value(); app_n3ds_hw_capabilities = n3ds_hw_caps.first.value();
if (!Settings::values.is_new_3ds.GetValue() && if (!Settings::values.is_new_3ds.GetValue() && app_loader->IsN3DSExclusive()) {
app_n3ds_hw_capabilities.memory_mode != Kernel::New3dsMemoryMode::Legacy) {
return ResultStatus::ErrorN3DSApplication; return ResultStatus::ErrorN3DSApplication;
} }
@@ -374,14 +373,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
// proper memory mode. // proper memory mode.
if (used_default_mem_mode) { if (used_default_mem_mode) {
// If we are on the Old 3DS prod mode, the application is not a New 3DS application and // If we are on the Old 3DS prod mode and the application memory mode does not match, we
// the application memory mode does not match, we need to adjust it. We do not need // need to adjust it. We do not need adjustment if we are on the New 3DS prod mode, as that
// adjustment if we are on the New 3DS prod mode, as that one overrides all the Old 3DS // one overrides all the Old 3DS memory modes.
// memory modes. if (system_mem_mode == Kernel::MemoryMode::Prod && app_mem_mode != system_mem_mode) {
if (system_mem_mode == Kernel::MemoryMode::Prod &&
app_n3ds_hw_capabilities.memory_mode == Kernel::New3dsMemoryMode::Legacy &&
app_mem_mode != system_mem_mode) {
system_mem_mode = app_mem_mode; system_mem_mode = app_mem_mode;
} }
@@ -389,7 +384,6 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
// memory mode (only CTRAging is known to do this), adjust the memory mode. // memory mode (only CTRAging is known to do this), adjust the memory mode.
else if (system_mem_mode == Kernel::MemoryMode::NewProd && else if (system_mem_mode == Kernel::MemoryMode::NewProd &&
app_n3ds_hw_capabilities.memory_mode == Kernel::New3dsMemoryMode::NewDev1) { app_n3ds_hw_capabilities.memory_mode == Kernel::New3dsMemoryMode::NewDev1) {
system_mem_mode = Kernel::MemoryMode::NewDev1; system_mem_mode = Kernel::MemoryMode::NewDev1;
} }
} }
+4 -1
View File
@@ -7,6 +7,7 @@
#include <boost/serialization/vector.hpp> #include <boost/serialization/vector.hpp>
#include "common/archives.h" #include "common/archives.h"
#include "common/serialization/atomic.h" #include "common/serialization/atomic.h"
#include "common/settings.h"
#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/config_mem.h"
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
@@ -172,7 +173,9 @@ void KernelSystem::ResetThreadIDs() {
void KernelSystem::UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode, void KernelSystem::UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode,
New3dsHwCapabilities n3ds_hw_cap) { New3dsHwCapabilities n3ds_hw_cap) {
SetRunning804MHz(n3ds_hw_cap.enable_804MHz_cpu); if (Settings::values.is_new_3ds) {
SetRunning804MHz(n3ds_hw_cap.enable_804MHz_cpu);
}
u32 tid_high = static_cast<u32>(title_id >> 32); u32 tid_high = static_cast<u32>(title_id >> 32);
+10
View File
@@ -134,6 +134,16 @@ Apploader_Artic::LoadNew3dsHwCapabilities() {
return std::make_pair(std::move(caps), ResultStatus::Success); return std::make_pair(std::move(caps), ResultStatus::Success);
} }
bool Apploader_Artic::IsN3DSExclusive() {
std::vector<u8> smdh_buffer;
if (ReadIcon(smdh_buffer) == ResultStatus::Success && IsValidSMDH(smdh_buffer)) {
SMDH* smdh = reinterpret_cast<SMDH*>(smdh_buffer.data());
return smdh->flags.n3ds_exclusive != 0;
}
return false;
}
ResultStatus Apploader_Artic::LoadExec(std::shared_ptr<Kernel::Process>& process) { ResultStatus Apploader_Artic::LoadExec(std::shared_ptr<Kernel::Process>& process) {
if (!is_loaded) if (!is_loaded)
+2
View File
@@ -56,6 +56,8 @@ public:
std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities() std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities()
override; override;
bool IsN3DSExclusive() override;
ResultStatus IsExecutable(bool& out_executable) override; ResultStatus IsExecutable(bool& out_executable) override;
ResultStatus ReadCode(std::vector<u8>& buffer) override; ResultStatus ReadCode(std::vector<u8>& buffer) override;
+4
View File
@@ -163,6 +163,10 @@ public:
ResultStatus::Success); ResultStatus::Success);
} }
virtual bool IsN3DSExclusive() {
return false;
}
/** /**
* Get whether this application is executable. * Get whether this application is executable.
* @param out_executable Reference to store the executable flag into. * @param out_executable Reference to store the executable flag into.
+17
View File
@@ -125,6 +125,23 @@ AppLoader_NCCH::LoadNew3dsHwCapabilities() {
return std::make_pair(std::move(caps), ResultStatus::Success); return std::make_pair(std::move(caps), ResultStatus::Success);
} }
bool AppLoader_NCCH::IsN3DSExclusive() {
if (!is_loaded) {
ResultStatus res = base_ncch.Load();
if (res != ResultStatus::Success) {
return false;
}
}
std::vector<u8> smdh_buffer;
if (ReadIcon(smdh_buffer) == ResultStatus::Success && IsValidSMDH(smdh_buffer)) {
SMDH* smdh = reinterpret_cast<SMDH*>(smdh_buffer.data());
return smdh->flags.n3ds_exclusive != 0;
}
return false;
}
ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) { ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) {
using Kernel::CodeSet; using Kernel::CodeSet;
+2
View File
@@ -50,6 +50,8 @@ public:
std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities() std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities()
override; override;
bool IsN3DSExclusive() override;
ResultStatus IsExecutable(bool& out_executable) override; ResultStatus IsExecutable(bool& out_executable) override;
ResultStatus ReadCode(std::vector<u8>& buffer) override; ResultStatus ReadCode(std::vector<u8>& buffer) override;
+18 -5
View File
@@ -7,6 +7,7 @@
#include <array> #include <array>
#include <span> #include <span>
#include <vector> #include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/swap.h" #include "common/swap.h"
@@ -37,7 +38,23 @@ struct SMDH {
u32_le region_lockout; u32_le region_lockout;
u32_le match_maker_id; u32_le match_maker_id;
u64_le match_maker_bit_id; u64_le match_maker_bit_id;
u32_le flags; union {
u32_le raw;
BitField<0, 1, u32> visible;
BitField<1, 1, u32> autoboot;
BitField<2, 1, u32> allow_3D;
BitField<3, 1, u32> require_eula;
BitField<4, 1, u32> autosave;
BitField<5, 1, u32> extended_banner;
BitField<6, 1, u32> rating_required;
BitField<7, 1, u32> uses_savedata;
BitField<8, 1, u32> record_usage;
BitField<10, 1, u32> disable_save_backup;
BitField<12, 1, u32> n3ds_exclusive;
BitField<14, 1, u32> parental_restricted;
} flags;
u16_le eula_version; u16_le eula_version;
INSERT_PADDING_BYTES(2); INSERT_PADDING_BYTES(2);
float_le banner_animation_frame; float_le banner_animation_frame;
@@ -73,10 +90,6 @@ struct SMDH {
Taiwan = 6, Taiwan = 6,
}; };
enum Flags {
Visible = 1 << 0,
};
/** /**
* Checks if SMDH is valid. * Checks if SMDH is valid.
*/ */