core: Fix memory mode handling during app launch (#1534)

This commit is contained in:
PabloMK7 2025-12-27 13:38:06 +01:00 committed by GitHub
parent f60f3eed1f
commit 8384eaa0c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 467 additions and 125 deletions

View File

@ -272,6 +272,12 @@ object NativeLibrary {
canContinue = false
}
CoreError.ErrorN3DSApplication -> {
title = emulationActivity.getString(R.string.invalid_system_mode)
message = emulationActivity.getString(R.string.invalid_system_mode_message)
canContinue = false
}
CoreError.ErrorUnknown -> {
title = emulationActivity.getString(R.string.fatal_error)
message = emulationActivity.getString(R.string.fatal_error_message)
@ -729,6 +735,7 @@ object NativeLibrary {
ErrorSystemFiles,
ErrorSavestate,
ErrorArticDisconnected,
ErrorN3DSApplication,
ErrorUnknown
}

View File

@ -95,6 +95,7 @@ static jobject ToJavaCoreError(Core::System::ResultStatus result) {
{Core::System::ResultStatus::ErrorSystemFiles, "ErrorSystemFiles"},
{Core::System::ResultStatus::ErrorSavestate, "ErrorSavestate"},
{Core::System::ResultStatus::ErrorArticDisconnected, "ErrorArticDisconnected"},
{Core::System::ResultStatus::ErrorN3DSApplication, "ErrorN3DSApplication"},
{Core::System::ResultStatus::ErrorUnknown, "ErrorUnknown"},
};

View File

@ -559,6 +559,8 @@
<string name="fatal_error">Fatal Error</string>
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string>
<string name="unsupported_encrypted">Unsupported encrypted application</string>
<string name="invalid_system_mode">Invalid system mode</string>
<string name="invalid_system_mode_message">New 3DS exclusive applications cannot be loaded without enabling the New 3DS mode.</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Preparing Shaders</string>

View File

@ -1313,6 +1313,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
system.GetStatusDetails())
.c_str()));
break;
case Core::System::ResultStatus::ErrorN3DSApplication:
QMessageBox::critical(this, tr("Invalid system mode"),
tr("New 3DS exclusive applications cannot be loaded without "
"enabling the New 3DS mode."));
break;
default:
QMessageBox::critical(
this, tr("Error while loading App!"),

View File

@ -27,6 +27,7 @@
#include "core/frontend/image_interface.h"
#include "core/gdbstub/gdbstub.h"
#include "core/global.h"
#include "core/hle/kernel/ipc_debugger/recorder.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
@ -317,49 +318,110 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
}
}
auto memory_mode = app_loader->LoadKernelMemoryMode();
if (memory_mode.second != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(memory_mode.second));
Kernel::MemoryMode app_mem_mode;
Kernel::MemoryMode system_mem_mode;
bool used_default_mem_mode = false;
Kernel::New3dsHwCapabilities app_n3ds_hw_capabilities;
switch (memory_mode.second) {
case Loader::ResultStatus::ErrorEncrypted:
return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorGbaTitle:
return ResultStatus::ErrorLoader_ErrorGbaTitle;
case Loader::ResultStatus::ErrorArtic:
return ResultStatus::ErrorArticDisconnected;
default:
return ResultStatus::ErrorSystemMode;
if (m_mem_mode) {
// Use memory mode set by the FIRM launch parameters
system_mem_mode = static_cast<Kernel::MemoryMode>(m_mem_mode.value());
m_mem_mode = {};
} else {
// Use default memory mode based on the n3ds setting
system_mem_mode = Settings::values.is_new_3ds.GetValue() ? Kernel::MemoryMode::NewProd
: Kernel::MemoryMode::Prod;
used_default_mem_mode = true;
}
{
auto memory_mode = app_loader->LoadKernelMemoryMode();
if (memory_mode.second != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(memory_mode.second));
switch (memory_mode.second) {
case Loader::ResultStatus::ErrorEncrypted:
return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorGbaTitle:
return ResultStatus::ErrorLoader_ErrorGbaTitle;
case Loader::ResultStatus::ErrorArtic:
return ResultStatus::ErrorArticDisconnected;
default:
return ResultStatus::ErrorSystemMode;
}
}
ASSERT(memory_mode.first);
app_mem_mode = memory_mode.first.value();
}
auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities();
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) {
return ResultStatus::ErrorN3DSApplication;
}
// If the default mem mode has been used, we do not come from a FIRM launch. On real HW
// however, the home menu is in charge or setting the proper memory mode when launching
// applications by doing a FIRM launch. Since we launch the application without going
// through the home menu, we need to emulate the FIRM launch having happened and set the
// 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) {
system_mem_mode = app_mem_mode;
}
// If we are on the New 3DS prod mode, and the application needs the New 3DS extended
// 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;
}
}
ASSERT(memory_mode.first);
auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities();
ASSERT(n3ds_hw_caps.first);
u32 num_cores = 2;
if (Settings::values.is_new_3ds) {
num_cores = 4;
}
ResultStatus init_result{
Init(emu_window, secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores)};
ResultStatus init_result{Init(emu_window, secondary_window, system_mem_mode, num_cores)};
if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<u32>(init_result));
System::Shutdown();
return init_result;
}
kernel->UpdateCPUAndMemoryState(program_id, app_mem_mode, app_n3ds_hw_capabilities);
gpu->ReportLoadingProgramID(program_id);
// Restore any parameters that should be carried through a reset.
if (restore_deliver_arg.has_value()) {
if (auto apt = Service::APT::GetModule(*this)) {
if (auto apt = Service::APT::GetModule(*this)) {
if (restore_deliver_arg.has_value()) {
apt->GetAppletManager()->SetDeliverArg(restore_deliver_arg);
restore_deliver_arg.reset();
}
if (restore_sys_menu_arg.has_value()) {
apt->GetAppletManager()->SetSysMenuArg(restore_sys_menu_arg.value());
restore_sys_menu_arg.reset();
}
restore_deliver_arg.reset();
}
if (restore_plugin_context.has_value()) {
if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
plg_ldr->SetPluginLoaderContext(restore_plugin_context.value());
@ -367,6 +429,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
restore_plugin_context.reset();
}
if (restore_ipc_recorder) {
kernel->RestoreIPCRecorder(std::move(restore_ipc_recorder));
}
std::shared_ptr<Kernel::Process> process;
const Loader::ResultStatus load_result{app_loader->Load(process)};
if (Loader::ResultStatus::Success != load_result) {
@ -449,8 +515,7 @@ void System::Reschedule() {
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
Frontend::EmuWindow* secondary_window,
Kernel::MemoryMode memory_mode,
const Kernel::New3dsHwCapabilities& n3ds_hw_caps, u32 num_cores) {
Kernel::MemoryMode memory_mode, u32 num_cores) {
LOG_DEBUG(HW_Memory, "initialized OK");
memory = std::make_unique<Memory::MemorySystem>(*this);
@ -459,7 +524,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
movie.GetOverrideBaseTicks());
kernel = std::make_unique<Kernel::KernelSystem>(
*memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps,
*memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores,
movie.GetOverrideInitTime());
exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores);
@ -678,11 +743,14 @@ void System::Reset() {
// This is needed as we don't currently support proper app jumping.
if (auto apt = Service::APT::GetModule(*this)) {
restore_deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
restore_sys_menu_arg = apt->GetAppletManager()->GetSysMenuArg();
}
if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
restore_plugin_context = plg_ldr->GetPluginLoaderContext();
}
restore_ipc_recorder = std::move(kernel->BackupIPCRecorder());
Shutdown();
if (!m_chainloadpath.empty()) {
@ -775,17 +843,19 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
}
ar & lle_modules;
Kernel::MemoryMode mem_mode{};
if (!Archive::is_loading::value) {
mem_mode = kernel->GetMemoryMode();
}
ar & mem_mode;
if (Archive::is_loading::value) {
// When loading, we want to make sure any lingering state gets cleared out before we begin.
// Shutdown, but persist a few things between loads...
Shutdown(true);
// Re-initialize everything like it was before
auto memory_mode = this->app_loader->LoadKernelMemoryMode();
auto n3ds_hw_caps = this->app_loader->LoadNew3dsHwCapabilities();
[[maybe_unused]] const System::ResultStatus result = Init(
*m_emu_window, m_secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores);
[[maybe_unused]] const System::ResultStatus result =
Init(*m_emu_window, m_secondary_window, mem_mode, num_cores);
}
// Flush on save, don't flush on load

View File

@ -101,6 +101,7 @@ public:
ErrorSystemFiles, ///< Error in finding system files
ErrorSavestate, ///< Error saving or loading
ErrorArticDisconnected, ///< Error when artic base disconnects
ErrorN3DSApplication, ///< Error launching New 3DS application in Old 3DS mode
ShutdownRequested, ///< Emulated program requested a system shutdown
ErrorUnknown ///< Any other error
};
@ -137,8 +138,9 @@ public:
bool SendSignal(Signal signal, u32 param = 0);
/// Request reset of the system
void RequestReset(const std::string& chainload = "") {
void RequestReset(const std::string& chainload = "", std::optional<u8> mem_mode = {}) {
m_chainloadpath = chainload;
m_mem_mode = mem_mode;
SendSignal(Signal::Reset);
}
@ -386,9 +388,7 @@ private:
*/
[[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window,
Frontend::EmuWindow* secondary_window,
Kernel::MemoryMode memory_mode,
const Kernel::New3dsHwCapabilities& n3ds_hw_caps,
u32 num_cores);
Kernel::MemoryMode memory_mode, u32 num_cores);
/// Reschedule the core emulation
void Reschedule();
@ -463,6 +463,7 @@ private:
Frontend::EmuWindow* m_secondary_window;
std::string m_filepath;
std::string m_chainloadpath;
std::optional<u8> m_mem_mode;
u64 title_id;
bool self_delete_pending;
@ -474,7 +475,9 @@ private:
bool mic_permission_granted = false;
boost::optional<Service::APT::DeliverArg> restore_deliver_arg;
boost::optional<Service::APT::SysMenuArg> restore_sys_menu_arg;
boost::optional<Service::PLGLDR::PLG_LDR::PluginLoaderContext> restore_plugin_context;
std::unique_ptr<IPCDebugger::Recorder> restore_ipc_recorder;
std::vector<u64> lle_modules;

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -26,14 +26,13 @@ namespace Kernel {
/// Initialize the kernel
KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
std::function<void()> prepare_reschedule_callback,
MemoryMode memory_mode, u32 num_cores,
const New3dsHwCapabilities& n3ds_hw_caps, u64 override_init_time)
MemoryMode memory_mode, u32 num_cores, u64 override_init_time)
: memory(memory), timing(timing),
prepare_reschedule_callback(std::move(prepare_reschedule_callback)), memory_mode(memory_mode),
n3ds_hw_caps(n3ds_hw_caps) {
prepare_reschedule_callback(std::move(prepare_reschedule_callback)),
memory_mode(memory_mode) {
std::generate(memory_regions.begin(), memory_regions.end(),
[] { return std::make_shared<MemoryRegionInfo>(); });
MemoryInit(memory_mode, n3ds_hw_caps.memory_mode, override_init_time);
MemoryInit(memory_mode, override_init_time);
resource_limits = std::make_unique<ResourceLimitList>(*this);
for (u32 core_id = 0; core_id < num_cores; ++core_id) {
@ -151,6 +150,14 @@ const IPCDebugger::Recorder& KernelSystem::GetIPCRecorder() const {
return *ipc_recorder;
}
std::unique_ptr<IPCDebugger::Recorder> KernelSystem::BackupIPCRecorder() {
return std::move(ipc_recorder);
}
void KernelSystem::RestoreIPCRecorder(std::unique_ptr<IPCDebugger::Recorder> recorder) {
ipc_recorder = std::move(recorder);
}
void KernelSystem::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
named_ports.emplace(std::move(name), std::move(port));
}
@ -163,6 +170,35 @@ void KernelSystem::ResetThreadIDs() {
next_thread_id = 0;
}
void KernelSystem::UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode,
New3dsHwCapabilities n3ds_hw_cap) {
SetRunning804MHz(n3ds_hw_cap.enable_804MHz_cpu);
u32 tid_high = static_cast<u32>(title_id >> 32);
constexpr u32 TID_HIGH_APPLET = 0x00040030;
constexpr u32 TID_HIGH_SYSMODULE = 0x00040130;
// PM only updates the reported memory for normal applications.
// TODO(PabloMK7): Using the title ID is not correct, but close enough.
if (tid_high != TID_HIGH_APPLET && tid_high != TID_HIGH_SYSMODULE) {
UpdateReportedMemory(memory_mode, n3ds_hw_cap.memory_mode);
}
}
void KernelSystem::RestoreMemoryState(u64 title_id) {
u32 tid_high = static_cast<u32>(title_id >> 32);
constexpr u32 TID_HIGH_APPLET = 0x00040030;
constexpr u32 TID_HIGH_SYSMODULE = 0x00040130;
// PM only updates the reported memory for normal applications.
// TODO(PabloMK7): Using the title ID is not correct, but close enough.
if (tid_high != TID_HIGH_APPLET && tid_high != TID_HIGH_SYSMODULE) {
RestoreReportedMemory();
}
}
template <class Archive>
void KernelSystem::serialize(Archive& ar, const unsigned int) {
ar & memory_regions;
@ -184,7 +220,7 @@ void KernelSystem::serialize(Archive& ar, const unsigned int) {
ar & stored_processes;
ar & next_thread_id;
ar & memory_mode;
ar & n3ds_hw_caps;
ar & running_804MHz;
ar & main_thread_extended_sleep;
// Deliberately don't include debugger info to allow debugging through loads

View File

@ -111,6 +111,9 @@ enum class MemoryMode : u8 {
Dev2 = 3, ///< 80MB app memory
Dev3 = 4, ///< 72MB app memory
Dev4 = 5, ///< 32MB app memory
NewProd = 6, ///< 124MB app memory
NewDev1 = 7, ///< 178MB app memory
};
/// New 3DS memory modes.
@ -137,8 +140,7 @@ class KernelSystem {
public:
explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
std::function<void()> prepare_reschedule_callback, MemoryMode memory_mode,
u32 num_cores, const New3dsHwCapabilities& n3ds_hw_caps,
u64 override_init_time = 0);
u32 num_cores, u64 override_init_time = 0);
~KernelSystem();
using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>;
@ -305,6 +307,8 @@ public:
IPCDebugger::Recorder& GetIPCRecorder();
const IPCDebugger::Recorder& GetIPCRecorder() const;
std::unique_ptr<IPCDebugger::Recorder> BackupIPCRecorder();
void RestoreIPCRecorder(std::unique_ptr<IPCDebugger::Recorder> recorder);
std::shared_ptr<MemoryRegionInfo> GetMemoryRegion(MemoryRegion region);
@ -327,8 +331,12 @@ public:
return memory_mode;
}
const New3dsHwCapabilities& GetNew3dsHwCapabilities() const {
return n3ds_hw_caps;
void SetRunning804MHz(bool enable) {
running_804MHz = enable;
}
bool GetRunning804MHz() const {
return running_804MHz;
}
std::recursive_mutex& GetHLELock() {
@ -365,8 +373,16 @@ public:
return pending_async_operations != 0;
}
void UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode,
New3dsHwCapabilities n3ds_hw_cap);
void RestoreMemoryState(u64 title_id);
private:
void MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode, u64 override_init_time);
void MemoryInit(MemoryMode memory_mode, u64 override_init_time);
void UpdateReportedMemory(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode);
void RestoreReportedMemory();
std::function<void()> prepare_reschedule_callback;
@ -404,7 +420,7 @@ private:
u32 next_thread_id;
MemoryMode memory_mode;
New3dsHwCapabilities n3ds_hw_caps;
bool running_804MHz = false;
/*
* Synchronizes access to the internal HLE kernel structures, it is acquired when a guest

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -41,23 +41,9 @@ static const u32 memory_region_sizes[8][3] = {
{0x0B200000, 0x02E00000, 0x02000000}, // 7
};
void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode,
u64 override_init_time) {
void KernelSystem::MemoryInit(MemoryMode memory_mode, u64 override_init_time) {
const bool is_new_3ds = Settings::values.is_new_3ds.GetValue();
u32 mem_type_index = static_cast<u32>(memory_mode);
u32 reported_mem_type = static_cast<u32>(memory_mode);
if (is_new_3ds) {
if (n3ds_mode == New3dsMemoryMode::NewProd || n3ds_mode == New3dsMemoryMode::NewDev2) {
mem_type_index = 6;
reported_mem_type = 6;
} else if (n3ds_mode == New3dsMemoryMode::NewDev1) {
mem_type_index = 7;
reported_mem_type = 7;
} else {
// On the N3ds, all O3ds configurations (<=5) are forced to 6 instead.
mem_type_index = 6;
}
}
const u32 mem_type_index = static_cast<u32>(memory_mode);
// The kernel allocation regions (APPLICATION, SYSTEM and BASE) are laid out in sequence, with
// the sizes specified in the memory_region_sizes table.
@ -73,14 +59,41 @@ void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode
config_mem_handler = std::make_shared<ConfigMem::Handler>();
auto& config_mem = config_mem_handler->GetConfigMem();
config_mem.app_mem_type = reported_mem_type;
config_mem.app_mem_alloc = memory_region_sizes[reported_mem_type][0];
config_mem.app_mem_type = static_cast<u8>(memory_mode);
config_mem.app_mem_alloc = memory_regions[0]->size;
config_mem.sys_mem_alloc = memory_regions[1]->size;
config_mem.base_mem_alloc = memory_regions[2]->size;
shared_page_handler = std::make_shared<SharedPage::Handler>(timing, override_init_time);
}
void KernelSystem::UpdateReportedMemory(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode) {
// If we are in New 3DS prod memory mode, and the application n3ds memory mode is set to legacy
// (all Old 3DS applications), then update reported available memory to the proper one according
// to the memory mode.
// This is normally done by PM when launching applications using svcSetResourceLimitLimitValues,
// but we do not implement that.
if (GetMemoryMode() == Kernel::MemoryMode::NewProd &&
n3ds_mode == Kernel::New3dsMemoryMode::Legacy) {
const u32 mem_type_index = static_cast<u32>(memory_mode);
auto& config_mem = config_mem_handler->GetConfigMem();
config_mem.app_mem_alloc = memory_region_sizes[mem_type_index][0];
}
}
void KernelSystem::RestoreReportedMemory() {
// If we are on New 3DS prod memory mode and we have terminated a process, restore the available
// memory to the proper size.
// This is normally done by PM when the application ends using svcSetResourceLimitLimitValues,
// but we do not implement that.
auto mem_mode = GetMemoryMode();
if (mem_mode == Kernel::MemoryMode::NewProd) {
const u32 mem_type_index = static_cast<u32>(mem_mode);
auto& config_mem = config_mem_handler->GetConfigMem();
config_mem.app_mem_alloc = memory_region_sizes[mem_type_index][0];
}
}
std::shared_ptr<MemoryRegionInfo> KernelSystem::GetMemoryRegion(MemoryRegion region) {
switch (region) {
case MemoryRegion::APPLICATION:

View File

@ -1,4 +1,4 @@
// Copyright 2015 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -124,6 +124,8 @@ void KernelSystem::TerminateProcess(std::shared_ptr<Process> process) {
GetThreadManager(core).TerminateProcessThreads(process);
}
RestoreMemoryState(process->codeset->program_id);
process->Exit();
std::erase(process_list, process);
}

View File

@ -122,6 +122,37 @@ static u64 GetTitleIdForApplet(AppletId id, u32 region_value) {
return itr->title_ids[region_value];
}
static constexpr std::size_t NumTitleIDConverts = 3;
static constexpr std::array<std::array<u64, 7>, NumTitleIDConverts> TitleIDConvertTable = {{
// MSET
{{0x0004001000020000, 0x0004001000021000, 0x0004001000022000, 0x0004001000020000,
0x0004001000026000, 0x0004001000027000, 0x0004001000028000}},
// eShop
{{0x0004001000020900, 0x0004001000021900, 0x0004001000022900, 0x0004001000020900,
0x0004001000020900, 0x0004001000027900, 0x0004001000028900}},
// NNID Settings
{{0x000400100002BF00, 0x000400100002C000, 0x000400100002C100, 0x000400100002BF00,
0x000400100002BF00, 0x000400100002BF00, 0x000400100002BF00}},
}};
static u64 ConvertTitleID(Core::System& system, u64 base_title_id) {
auto cfg = Service::CFG::GetModule(system);
if (!cfg) {
return base_title_id;
}
u32 region_value = cfg->GetRegionValue(false);
for (auto& entry : TitleIDConvertTable) {
if (base_title_id == entry[0]) {
return entry[region_value];
}
}
return base_title_id;
}
static bool IsSystemAppletId(AppletId applet_id) {
return (static_cast<u32>(applet_id) & static_cast<u32>(AppletId::AnySystemApplet)) != 0;
}
@ -1013,6 +1044,22 @@ Result AppletManager::LeaveHomeMenu(std::shared_ptr<Kernel::Object> object,
return ResultSuccess;
}
Result AppletManager::LoadSysMenuArg(std::vector<u8>& buffer) {
if (sys_menu_arg.has_value()) {
std::memcpy(buffer.data(), sys_menu_arg.value().data(),
std::min(buffer.size(), sys_menu_arg.value().size()));
}
// Always succeed, even if there is no data to copy.
return ResultSuccess;
}
Result AppletManager::StoreSysMenuArg(const std::vector<u8>& buffer) {
sys_menu_arg = std::array<u8, SysMenuArgSize>();
std::memcpy(sys_menu_arg.value().data(), buffer.data(),
std::min(buffer.size(), sys_menu_arg.value().size()));
return ResultSuccess;
}
Result AppletManager::OrderToCloseApplication() {
if (active_slot == AppletSlot::Error) {
return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState,
@ -1213,8 +1260,8 @@ ApplicationRunningMode AppletManager::GetApplicationRunningMode() {
// APT checks whether the system is a New 3DS and the 804MHz CPU speed is enabled to determine
// the result.
auto new_3ds_mode = GetTargetPlatform() == TargetPlatform::New3ds &&
system.Kernel().GetNew3dsHwCapabilities().enable_804MHz_cpu;
auto new_3ds_mode =
GetTargetPlatform() == TargetPlatform::New3ds && system.Kernel().GetRunning804MHz();
if (slot_data->registered) {
return new_3ds_mode ? ApplicationRunningMode::New3dsRegistered
: ApplicationRunningMode::Old3dsRegistered;
@ -1242,7 +1289,7 @@ Result AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType med
app_jump_parameters.next_title_id = app_jump_parameters.current_title_id;
app_jump_parameters.next_media_type = app_jump_parameters.current_media_type;
} else {
app_jump_parameters.next_title_id = title_id;
app_jump_parameters.next_title_id = ConvertTitleID(system, title_id);
app_jump_parameters.next_media_type = media_type;
}
app_jump_parameters.flags = flags;
@ -1301,7 +1348,7 @@ Result AppletManager::DoApplicationJump(const DeliverArg& arg) {
*/
NS::RebootToTitle(system, app_jump_parameters.next_media_type,
app_jump_parameters.next_title_id);
app_jump_parameters.next_title_id, std::nullopt);
return ResultSuccess;
}
}
@ -1320,6 +1367,53 @@ Result AppletManager::PrepareToStartApplication(u64 title_id, FS::MediaType medi
ErrorLevel::Status};
}
title_id = ConvertTitleID(system, title_id);
std::string path = AM::GetTitleContentPath(media_type, title_id);
auto loader = Loader::GetLoader(path);
if (!loader) {
LOG_ERROR(Service_APT, "Could not find .app for title 0x{:016x}", title_id);
// TODO: Find proper error code
return ResultUnknown;
}
auto plg_ldr = Service::PLGLDR::GetService(system);
if (plg_ldr) {
const auto& plg_context = plg_ldr->GetPluginLoaderContext();
if (plg_context.is_enabled && plg_context.use_user_load_parameters &&
plg_context.user_load_parameters.low_title_Id == static_cast<u32>(title_id) &&
plg_context.user_load_parameters.plugin_memory_strategy ==
PLGLDR::PLG_LDR::PluginMemoryStrategy::PLG_STRATEGY_MODE3) {
loader->SetKernelMemoryModeOverride(Kernel::MemoryMode::Dev2);
}
}
auto mem_mode = loader->LoadKernelMemoryMode();
if (mem_mode.second != Loader::ResultStatus::Success || !mem_mode.first.has_value()) {
// This cannot happen on real HW at this point of execution
LOG_ERROR(Service_APT, "Could not determine memory mode");
return ResultUnknown;
}
auto curr_mem_mode = system.Kernel().GetMemoryMode();
if (mem_mode.first.value() != curr_mem_mode) {
if (system.Kernel().GetMemoryMode() == Kernel::MemoryMode::NewProd) {
// On New 3DS prod memory mode, only incorrect state is if the app
// reports having the "unused" memory mode 1. TODO: Figure out
// how this works and if it is even used.
if (mem_mode.first.value() == static_cast<Kernel::MemoryMode>(1)) {
return {ErrCodes::IncorrectMemoryMode, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status};
}
} else {
// On other memory modes, the state is incorrect.
return {ErrCodes::IncorrectMemoryMode, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
}
ASSERT_MSG(!app_start_parameters,
"Trying to prepare an application when another is already prepared");
@ -1403,6 +1497,44 @@ Result AppletManager::CancelApplication() {
return ResultSuccess;
}
Result AppletManager::PrepareToStartNewestHomeMenu() {
if (active_slot == AppletSlot::Error ||
GetAppletSlot(active_slot)->attributes.applet_pos != AppletPos::System) {
return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
bool is_standard;
if (Settings::values.is_new_3ds) {
// Memory layout is standard if it is not NewDev1 (178MB)
is_standard = system.Kernel().GetMemoryMode() != Kernel::MemoryMode::NewDev1;
} else {
// Memory layout is standard if it is Prod (64MB)
is_standard = system.Kernel().GetMemoryMode() == Kernel::MemoryMode::Prod;
}
if (is_standard) {
return Result{ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status};
}
home_menu_tid_to_start = GetAppletSlot(active_slot)->title_id;
return ResultSuccess;
}
Result AppletManager::StartNewestHomeMenu() {
if (!home_menu_tid_to_start) {
return Result{ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status};
}
u64 titleID = home_menu_tid_to_start;
home_menu_tid_to_start = 0;
NS::RebootToTitle(system, Service::FS::MediaType::NAND, titleID, std::nullopt);
return ResultSuccess;
}
void AppletManager::SendApplicationParameterAfterRegistration(const MessageParameter& parameter) {
auto slot = GetAppletSlotFromId(parameter.destination_id);

View File

@ -1,4 +1,4 @@
// Copyright 2018 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -118,6 +118,8 @@ enum class ApplicationRunningMode : u8 {
New3dsUnregistered = 4,
};
constexpr std::size_t SysMenuArgSize = 0x40;
/// Holds information about the parameters used in Send/Glance/ReceiveParameter
struct MessageParameter {
AppletId sender_id = AppletId::None;
@ -180,6 +182,8 @@ private:
friend class boost::serialization::access;
};
using SysMenuArg = std::array<u8, SysMenuArgSize>;
struct ApplicationJumpParameters {
u64 next_title_id;
FS::MediaType next_media_type;
@ -322,6 +326,16 @@ public:
Result PrepareToLeaveHomeMenu();
Result LeaveHomeMenu(std::shared_ptr<Kernel::Object> object, const std::vector<u8>& buffer);
Result LoadSysMenuArg(std::vector<u8>& buffer);
Result StoreSysMenuArg(const std::vector<u8>& buffer);
boost::optional<SysMenuArg> GetSysMenuArg() {
return sys_menu_arg;
}
void SetSysMenuArg(const SysMenuArg& arg) {
sys_menu_arg = arg;
}
Result OrderToCloseApplication();
Result PrepareToCloseApplication(bool return_to_sys);
Result CloseApplication(std::shared_ptr<Kernel::Object> object, const std::vector<u8>& buffer);
@ -376,6 +390,9 @@ public:
Result WakeupApplication(std::shared_ptr<Kernel::Object> object, const std::vector<u8>& buffer);
Result CancelApplication();
Result PrepareToStartNewestHomeMenu();
Result StartNewestHomeMenu();
struct AppletManInfo {
AppletPos active_applet_pos;
AppletId requested_applet_id;
@ -417,6 +434,8 @@ private:
ApplicationJumpParameters app_jump_parameters{};
boost::optional<ApplicationStartParameters> app_start_parameters{};
boost::optional<DeliverArg> deliver_arg{};
boost::optional<SysMenuArg> sys_menu_arg{};
u64 home_menu_tid_to_start{};
boost::optional<CaptureBufferInfo> capture_info;
boost::optional<CaptureBufferInfo> capture_buffer_info;
@ -532,6 +551,8 @@ private:
ar & delayed_parameter;
ar & app_start_parameters;
ar & deliver_arg;
ar & sys_menu_arg;
ar & home_menu_tid_to_start;
ar & capture_info;
ar & capture_buffer_info;
ar & active_slot;

View File

@ -92,16 +92,15 @@ void Module::NSInterface::RebootSystem(Kernel::HLERequestContext& ctx) {
const auto title_id = rp.Pop<u64>();
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
rp.Skip(1, false); // Skip padding
// TODO: Utilize requested memory type.
const auto mem_type = rp.Pop<u8>();
LOG_WARNING(Service_APT,
"called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}",
launch_title, title_id, media_type, mem_type);
// TODO: Handle mem type.
if (launch_title) {
NS::RebootToTitle(apt->system, media_type, title_id);
NS::RebootToTitle(apt->system, media_type, title_id,
static_cast<Kernel::MemoryMode>(mem_type));
} else {
apt->system.RequestReset();
}
@ -763,16 +762,12 @@ void Module::APTInterface::PrepareToStartSystemApplet(Kernel::HLERequestContext&
void Module::APTInterface::PrepareToStartNewestHomeMenu(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
LOG_DEBUG(Service_APT, "called");
// TODO(Subv): This command can only be called by a System Applet (return 0xC8A0CC04 otherwise).
// This command must return an error when called, otherwise the Home Menu will try to reboot the
// system.
rb.Push(Result(ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status));
rb.Push(apt->applet_manager->PrepareToStartNewestHomeMenu());
}
void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx) {
@ -821,6 +816,19 @@ void Module::APTInterface::StartSystemApplet(Kernel::HLERequestContext& ctx) {
rb.Push(apt->applet_manager->StartSystemApplet(applet_id, object, buffer));
}
void Module::APTInterface::StartNewestHomeMenu(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto buffer_size = rp.Pop<u32>();
[[maybe_unused]] const auto object = rp.PopGenericObject();
[[maybe_unused]] const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called, size={:08X}", buffer_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->StartNewestHomeMenu());
}
void Module::APTInterface::OrderToCloseApplication(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
@ -1011,10 +1019,10 @@ void Module::APTInterface::LoadSysMenuArg(Kernel::HLERequestContext& ctx) {
// This service function does not clear the buffer.
std::vector<u8> buffer(size);
std::copy_n(apt->sys_menu_arg_buffer.cbegin(), size, buffer.begin());
Result res = apt->applet_manager->LoadSysMenuArg(buffer);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(ResultSuccess);
rb.Push(res);
rb.PushStaticBuffer(std::move(buffer), 0);
}
@ -1026,10 +1034,10 @@ void Module::APTInterface::StoreSysMenuArg(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_APT, "called");
ASSERT_MSG(buffer.size() >= size, "Buffer too small to hold requested data");
std::copy_n(buffer.cbegin(), size, apt->sys_menu_arg_buffer.begin());
Result res = apt->applet_manager->StoreSysMenuArg(buffer);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultSuccess);
rb.Push(res);
}
void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx) {
@ -1365,8 +1373,8 @@ void Module::APTInterface::Reboot(Kernel::HLERequestContext& ctx) {
"called title_id={:016X}, media_type={:02X}, mem_type={:02X}, firm_tid_low={:08X}",
title_id, media_type, mem_type, firm_tid_low);
// TODO: Handle mem type and FIRM TID low.
NS::RebootToTitle(apt->system, media_type, title_id);
// TODO: Handle FIRM TID low.
NS::RebootToTitle(apt->system, media_type, title_id, static_cast<Kernel::MemoryMode>(mem_type));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultSuccess);
@ -1420,8 +1428,7 @@ void Module::APTInterface::IsStandardMemoryLayout(Kernel::HLERequestContext& ctx
bool is_standard;
if (Settings::values.is_new_3ds) {
// Memory layout is standard if it is not NewDev1 (178MB)
is_standard = apt->system.Kernel().GetNew3dsHwCapabilities().memory_mode !=
Kernel::New3dsMemoryMode::NewDev1;
is_standard = apt->system.Kernel().GetMemoryMode() != Kernel::MemoryMode::NewDev1;
} else {
// Memory layout is standard if it is Prod (64MB)
is_standard = apt->system.Kernel().GetMemoryMode() == Kernel::MemoryMode::Prod;

View File

@ -1,4 +1,4 @@
// Copyright 2015 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -31,8 +31,6 @@ class AppletManager;
/// Each APT service can only have up to 2 sessions connected at the same time.
static const u32 MaxAPTSessions = 2;
constexpr std::size_t SysMenuArgSize = 0x40;
enum class StartupArgumentType : u32 {
OtherApp = 0,
Restart = 1,
@ -547,6 +545,21 @@ public:
*/
void StartSystemApplet(Kernel::HLERequestContext& ctx);
/**
* APT::StartNewestHomeMenu service function
* Inputs:
* 0 : Command header [0x00200044]
* 1 : Partameters size
* 2 : 0x0
* 3 : Handle parameter
* 4 : (Parameters Size << 14) | 2
* 5 : void*, Parameters
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
void StartNewestHomeMenu(Kernel::HLERequestContext& ctx);
/**
* APT::OrderToCloseApplication service function
* Inputs:
@ -1073,8 +1086,6 @@ private:
u32 cpu_percent = 0; ///< CPU time available to the running application
std::array<u8, SysMenuArgSize> sys_menu_arg_buffer;
ScreencapPostPermission screen_capture_post_permission =
ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -42,7 +42,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x001D, &APT_A::CancelApplication, "CancelApplication"},
{0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"},
{0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"},
{0x0020, nullptr, "StartNewestHomeMenu"},
{0x0020, &APT_A::StartNewestHomeMenu, "StartNewestHomeMenu"},
{0x0021, &APT_A::OrderToCloseApplication, "OrderToCloseApplication"},
{0x0022, &APT_A::PrepareToCloseApplication, "PrepareToCloseApplication"},
{0x0023, nullptr, "PrepareToJumpToApplication"},

View File

@ -1,4 +1,4 @@
// Copyright 2015 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -42,7 +42,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x001D, &APT_S::CancelApplication, "CancelApplication"},
{0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"},
{0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"},
{0x0020, nullptr, "StartNewestHomeMenu"},
{0x0020, &APT_S::StartNewestHomeMenu, "StartNewestHomeMenu"},
{0x0021, &APT_S::OrderToCloseApplication, "OrderToCloseApplication"},
{0x0022, &APT_S::PrepareToCloseApplication, "PrepareToCloseApplication"},
{0x0023, nullptr, "PrepareToJumpToApplication"},

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -42,7 +42,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x001D, &APT_U::CancelApplication, "CancelApplication"},
{0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"},
{0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"},
{0x0020, nullptr, "StartNewestHomeMenu"},
{0x0020, &APT_U::StartNewestHomeMenu, "StartNewestHomeMenu"},
{0x0021, &APT_U::OrderToCloseApplication, "OrderToCloseApplication"},
{0x0022, &APT_U::PrepareToCloseApplication, "PrepareToCloseApplication"},
{0x0023, nullptr, "PrepareToJumpToApplication"},

View File

@ -1,4 +1,4 @@
// Copyright 2018 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -8,6 +8,7 @@ namespace Service::APT::ErrCodes {
enum {
ParameterPresent = 2,
InvalidAppletSlot = 4,
IncorrectMemoryMode = 5,
AppNotRunning = 11,
};
} // namespace Service::APT::ErrCodes

View File

@ -1,4 +1,4 @@
// Copyright 2017 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -30,6 +30,23 @@ std::shared_ptr<Kernel::Process> LaunchTitle(Core::System& system, FS::MediaType
}
}
{
// This is normally done by PM, but we don't emulate it
// so we do it here instead.
auto mem_mode_res = loader->LoadKernelMemoryMode();
Kernel::MemoryMode mem_mode{};
auto n3ds_cap_res = loader->LoadNew3dsHwCapabilities();
Kernel::New3dsHwCapabilities n3ds_hw_cap{};
if (mem_mode_res.second == Loader::ResultStatus::Success && mem_mode_res.first) {
mem_mode = mem_mode_res.first.value();
}
if (n3ds_cap_res.second == Loader::ResultStatus::Success && n3ds_cap_res.first) {
n3ds_hw_cap = n3ds_cap_res.first.value();
}
system.Kernel().UpdateCPUAndMemoryState(title_id, mem_mode, n3ds_hw_cap);
}
std::shared_ptr<Kernel::Process> process;
Loader::ResultStatus result = loader->Load(process);
@ -41,7 +58,8 @@ std::shared_ptr<Kernel::Process> LaunchTitle(Core::System& system, FS::MediaType
return process;
}
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id) {
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id,
std::optional<Kernel::MemoryMode> mem_mode) {
auto new_path = AM::GetTitleContentPath(media_type, title_id);
if (new_path.empty() || !FileUtil::Exists(new_path)) {
// TODO: This can happen if the requested title is not installed. Need a way to find
@ -51,7 +69,12 @@ void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id)
new_path);
new_path.clear();
}
system.RequestReset(new_path);
std::optional<u8> mem_mode_u8;
if (mem_mode) {
mem_mode_u8 = static_cast<u8>(mem_mode.value());
}
system.RequestReset(new_path, mem_mode_u8);
}
} // namespace Service::NS

View File

@ -1,4 +1,4 @@
// Copyright 2017 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -20,6 +20,7 @@ std::shared_ptr<Kernel::Process> LaunchTitle(Core::System& system, FS::MediaType
u64 title_id);
/// Reboots the system to the specified title.
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id);
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id,
std::optional<Kernel::MemoryMode> mem_mode);
} // namespace Service::NS

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -22,8 +22,7 @@ TEST_CASE("DSP LLE vs HLE", "[audio_core][hle]") {
Memory::MemorySystem lle_memory{system};
Core::Timing lle_core_timing(1, 100);
Kernel::KernelSystem lle_kernel(
lle_memory, lle_core_timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
lle_memory, lle_core_timing, [] {}, Kernel::MemoryMode::NewProd, 1);
AudioCore::DspHle hle(system, hle_memory, hle_core_timing);
AudioCore::DspLle lle(system, lle_memory, lle_core_timing, true);

View File

@ -1,4 +1,4 @@
// Copyright 2017 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -23,9 +23,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
Core::Timing timing(1, 100);
Core::System system;
Memory::MemorySystem memory{system};
Kernel::KernelSystem kernel(
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1);
auto [server, client] = kernel.CreateSessionPair();
HLERequestContext context(kernel, std::move(server), nullptr);
@ -256,9 +254,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
Core::Timing timing(1, 100);
Core::System system;
Memory::MemorySystem memory{system};
Kernel::KernelSystem kernel(
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1);
auto [server, client] = kernel.CreateSessionPair();
HLERequestContext context(kernel, std::move(server), nullptr);

View File

@ -1,4 +1,4 @@
// Copyright 2017 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -12,9 +12,7 @@ TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") {
Core::Timing timing(1, 100);
Core::System system;
Memory::MemorySystem memory{system};
Kernel::KernelSystem kernel(
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1);
SECTION("these regions should not be mapped on an empty process") {
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);

View File

@ -1,4 +1,4 @@
// Copyright 2017 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -16,9 +16,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
Core::Timing timing(1, 100);
Core::System system;
Memory::MemorySystem memory{system};
Kernel::KernelSystem kernel(
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
Kernel::KernelSystem kernel(memory, timing, [] {}, Kernel::MemoryMode::NewProd, 1);
Kernel::Process process(kernel);
SECTION("mapping memory") {
// Because of the PageTable, Kernel::VMManager is too big to be created on the stack.