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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 64 additions and 19 deletions

View File

@ -222,7 +222,7 @@ jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsVisibleSystemTitle(JNIEnv
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) {

View File

@ -92,7 +92,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
if (Loader::IsValidSMDH(smdh)) {
if (system_title) {
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.
return true;
}

View File

@ -362,8 +362,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
ASSERT(n3ds_hw_caps.first);
app_n3ds_hw_capabilities = n3ds_hw_caps.first.value();
if (!Settings::values.is_new_3ds.GetValue() &&
app_n3ds_hw_capabilities.memory_mode != Kernel::New3dsMemoryMode::Legacy) {
if (!Settings::values.is_new_3ds.GetValue() && app_loader->IsN3DSExclusive()) {
return ResultStatus::ErrorN3DSApplication;
}
@ -374,14 +373,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
// proper memory mode.
if (used_default_mem_mode) {
// If we are on the Old 3DS prod mode, the application is not a New 3DS application and
// the application memory mode does not match, we need to adjust it. We do not need
// adjustment if we are on the New 3DS prod mode, as that one overrides all the Old 3DS
// memory modes.
if (system_mem_mode == Kernel::MemoryMode::Prod &&
app_n3ds_hw_capabilities.memory_mode == Kernel::New3dsMemoryMode::Legacy &&
app_mem_mode != system_mem_mode) {
// If we are on the Old 3DS prod mode and the application memory mode does not match, we
// need to adjust it. We do not need adjustment if we are on the New 3DS prod mode, as that
// one overrides all the Old 3DS memory modes.
if (system_mem_mode == Kernel::MemoryMode::Prod && app_mem_mode != system_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.
else if (system_mem_mode == Kernel::MemoryMode::NewProd &&
app_n3ds_hw_capabilities.memory_mode == Kernel::New3dsMemoryMode::NewDev1) {
system_mem_mode = Kernel::MemoryMode::NewDev1;
}
}

View File

@ -7,6 +7,7 @@
#include <boost/serialization/vector.hpp>
#include "common/archives.h"
#include "common/serialization/atomic.h"
#include "common/settings.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/config_mem.h"
#include "core/hle/kernel/handle_table.h"
@ -172,7 +173,9 @@ void KernelSystem::ResetThreadIDs() {
void KernelSystem::UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode,
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);

View File

@ -134,6 +134,16 @@ Apploader_Artic::LoadNew3dsHwCapabilities() {
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) {
if (!is_loaded)

View File

@ -56,6 +56,8 @@ public:
std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities()
override;
bool IsN3DSExclusive() override;
ResultStatus IsExecutable(bool& out_executable) override;
ResultStatus ReadCode(std::vector<u8>& buffer) override;

View File

@ -163,6 +163,10 @@ public:
ResultStatus::Success);
}
virtual bool IsN3DSExclusive() {
return false;
}
/**
* Get whether this application is executable.
* @param out_executable Reference to store the executable flag into.

View File

@ -125,6 +125,23 @@ AppLoader_NCCH::LoadNew3dsHwCapabilities() {
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) {
using Kernel::CodeSet;

View File

@ -50,6 +50,8 @@ public:
std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities()
override;
bool IsN3DSExclusive() override;
ResultStatus IsExecutable(bool& out_executable) override;
ResultStatus ReadCode(std::vector<u8>& buffer) override;

View File

@ -7,6 +7,7 @@
#include <array>
#include <span>
#include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
@ -37,7 +38,23 @@ struct SMDH {
u32_le region_lockout;
u32_le match_maker_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;
INSERT_PADDING_BYTES(2);
float_le banner_animation_frame;
@ -73,10 +90,6 @@ struct SMDH {
Taiwan = 6,
};
enum Flags {
Visible = 1 << 0,
};
/**
* Checks if SMDH is valid.
*/