summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt10
-rw-r--r--src/core/arm/arm_interface.cpp84
-rw-r--r--src/core/arm/arm_interface.h37
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h29
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp64
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h16
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp64
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h18
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.cpp (renamed from src/core/arm/dynarmic/arm_dynarmic_cp15.cpp)2
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.h (renamed from src/core/arm/dynarmic/arm_dynarmic_cp15.h)0
-rw-r--r--src/core/arm/dynarmic/dynarmic_exclusive_monitor.cpp (renamed from src/core/arm/dynarmic/arm_exclusive_monitor.cpp)2
-rw-r--r--src/core/arm/dynarmic/dynarmic_exclusive_monitor.h (renamed from src/core/arm/dynarmic/arm_exclusive_monitor.h)0
-rw-r--r--src/core/arm/exclusive_monitor.cpp2
-rw-r--r--src/core/core.cpp44
-rw-r--r--src/core/core.h11
-rw-r--r--src/core/crypto/key_manager.cpp8
-rw-r--r--src/core/crypto/key_manager.h3
-rw-r--r--src/core/device_memory.cpp8
-rw-r--r--src/core/file_sys/control_metadata.cpp12
-rw-r--r--src/core/file_sys/control_metadata.h4
-rw-r--r--src/core/file_sys/patch_manager.cpp33
-rw-r--r--src/core/file_sys/submission_package.h1
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/frontend/emu_window.h48
-rw-r--r--src/core/frontend/graphics_context.h62
-rw-r--r--src/core/hid/emulated_console.cpp32
-rw-r--r--src/core/hid/emulated_console.h4
-rw-r--r--src/core/hid/emulated_controller.cpp26
-rw-r--r--src/core/hid/emulated_controller.h2
-rw-r--r--src/core/hle/kernel/k_address_space_info.cpp5
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp1
-rw-r--r--src/core/hle/service/nfc/common/device.cpp160
-rw-r--r--src/core/hle/service/nfc/common/device.h10
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp14
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp8
-rw-r--r--src/core/hle/service/nfc/nfc_result.h20
-rw-r--r--src/core/hle/service/nfp/nfp_interface.cpp6
-rw-r--r--src/core/hle/service/nfp/nfp_result.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp4
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp4
-rw-r--r--src/core/loader/nro.cpp13
-rw-r--r--src/core/loader/nro.h2
42 files changed, 597 insertions, 280 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8e5334e02..227c431bc 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -4,8 +4,6 @@
add_library(core STATIC
arm/arm_interface.h
arm/arm_interface.cpp
- arm/dynarmic/arm_exclusive_monitor.cpp
- arm/dynarmic/arm_exclusive_monitor.h
arm/exclusive_monitor.cpp
arm/exclusive_monitor.h
arm/symbols.cpp
@@ -142,6 +140,7 @@ add_library(core STATIC
frontend/emu_window.h
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
+ frontend/graphics_context.h
hid/emulated_console.cpp
hid/emulated_console.h
hid/emulated_controller.cpp
@@ -848,12 +847,15 @@ endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_sources(core PRIVATE
+ arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h
arm/dynarmic/arm_dynarmic_32.cpp
arm/dynarmic/arm_dynarmic_32.h
- arm/dynarmic/arm_dynarmic_cp15.cpp
- arm/dynarmic/arm_dynarmic_cp15.h
+ arm/dynarmic/dynarmic_cp15.cpp
+ arm/dynarmic/dynarmic_cp15.h
+ arm/dynarmic/dynarmic_exclusive_monitor.cpp
+ arm/dynarmic/dynarmic_exclusive_monitor.h
hle/service/jit/jit_context.cpp
hle/service/jit/jit_context.h
hle/service/jit/jit.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index d30914b7a..beaea64b3 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -13,25 +13,68 @@
#include "core/core.h"
#include "core/debugger/debugger.h"
#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
#include "core/loader/loader.h"
#include "core/memory.h"
-#include "core/arm/dynarmic/arm_dynarmic_32.h"
-#include "core/arm/dynarmic/arm_dynarmic_64.h"
-
namespace Core {
constexpr u64 SEGMENT_BASE = 0x7100000000ull;
std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext(
Core::System& system, const ARM_Interface::ThreadContext32& ctx) {
- return ARM_Dynarmic_32::GetBacktraceFromContext(system, ctx);
+ std::vector<BacktraceEntry> out;
+ auto& memory = system.ApplicationMemory();
+
+ const auto& reg = ctx.cpu_registers;
+ u32 pc = reg[15], lr = reg[14], fp = reg[11];
+ out.push_back({"", 0, pc, 0, ""});
+
+ // fp (= r11) points to the last frame record.
+ // Frame records are two words long:
+ // fp+0 : pointer to previous frame record
+ // fp+4 : value of lr for frame
+ for (size_t i = 0; i < 256; i++) {
+ out.push_back({"", 0, lr, 0, ""});
+ if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
+ break;
+ }
+ lr = memory.Read32(fp + 4);
+ fp = memory.Read32(fp);
+ }
+
+ SymbolicateBacktrace(system, out);
+
+ return out;
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext(
Core::System& system, const ARM_Interface::ThreadContext64& ctx) {
- return ARM_Dynarmic_64::GetBacktraceFromContext(system, ctx);
+ std::vector<BacktraceEntry> out;
+ auto& memory = system.ApplicationMemory();
+
+ const auto& reg = ctx.cpu_registers;
+ u64 pc = ctx.pc, lr = reg[30], fp = reg[29];
+
+ out.push_back({"", 0, pc, 0, ""});
+
+ // fp (= x29) points to the previous frame record.
+ // Frame records are two words long:
+ // fp+0 : pointer to previous frame record
+ // fp+8 : value of lr for frame
+ for (size_t i = 0; i < 256; i++) {
+ out.push_back({"", 0, lr, 0, ""});
+ if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
+ break;
+ }
+ lr = memory.Read64(fp + 8);
+ fp = memory.Read64(fp);
+ }
+
+ SymbolicateBacktrace(system, out);
+
+ return out;
}
void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out) {
@@ -76,6 +119,18 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
}
}
+std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
+ if (GetArchitecture() == Architecture::Aarch64) {
+ ThreadContext64 ctx;
+ SaveContext(ctx);
+ return GetBacktraceFromContext(system, ctx);
+ } else {
+ ThreadContext32 ctx;
+ SaveContext(ctx);
+ return GetBacktraceFromContext(system, ctx);
+ }
+}
+
void ARM_Interface::LogBacktrace() const {
const VAddr sp = GetSP();
const VAddr pc = GetPC();
@@ -83,7 +138,6 @@ void ARM_Interface::LogBacktrace() const {
LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address",
"Offset", "Symbol");
LOG_ERROR(Core_ARM, "");
-
const auto backtrace = GetBacktrace();
for (const auto& entry : backtrace) {
LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
@@ -97,7 +151,7 @@ void ARM_Interface::Run() {
while (true) {
Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())};
- Dynarmic::HaltReason hr{};
+ HaltReason hr{};
// Notify the debugger and go to sleep if a step was performed
// and this thread has been scheduled again.
@@ -108,17 +162,17 @@ void ARM_Interface::Run() {
}
// Otherwise, run the thread.
- system.EnterDynarmicProfile();
+ system.EnterCPUProfile();
if (current_thread->GetStepState() == StepState::StepPending) {
hr = StepJit();
- if (Has(hr, step_thread)) {
+ if (True(hr & HaltReason::StepThread)) {
current_thread->SetStepState(StepState::StepPerformed);
}
} else {
hr = RunJit();
}
- system.ExitDynarmicProfile();
+ system.ExitCPUProfile();
// If the thread is scheduled for termination, exit the thread.
if (current_thread->HasDpc()) {
@@ -130,8 +184,8 @@ void ARM_Interface::Run() {
// Notify the debugger and go to sleep if a breakpoint was hit,
// or if the thread is unable to continue for any reason.
- if (Has(hr, breakpoint) || Has(hr, no_execute)) {
- if (!Has(hr, no_execute)) {
+ if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
+ if (!True(hr & HaltReason::InstructionBreakpoint)) {
RewindBreakpointInstruction();
}
if (system.DebuggerEnabled()) {
@@ -144,7 +198,7 @@ void ARM_Interface::Run() {
}
// Notify the debugger and go to sleep if a watchpoint was hit.
- if (Has(hr, watchpoint)) {
+ if (True(hr & HaltReason::DataAbort)) {
if (system.DebuggerEnabled()) {
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
}
@@ -153,11 +207,11 @@ void ARM_Interface::Run() {
}
// Handle syscalls and scheduling (this may change the current thread/core)
- if (Has(hr, svc_call)) {
+ if (True(hr & HaltReason::SupervisorCall)) {
Kernel::Svc::Call(system, GetSvcNumber());
break;
}
- if (Has(hr, break_loop) || !uses_wall_clock) {
+ if (True(hr & HaltReason::BreakLoop) || !uses_wall_clock) {
break;
}
}
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 8e40702cc..d5f2fa09a 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -8,8 +8,6 @@
#include <string>
#include <vector>
-#include <dynarmic/interface/halt_reason.h>
-
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hardware_properties.h"
@@ -30,6 +28,22 @@ class CPUInterruptHandler;
using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
+// NOTE: these values match the HaltReason enum in Dynarmic
+enum class HaltReason : u64 {
+ StepThread = 0x00000001,
+ DataAbort = 0x00000004,
+ BreakLoop = 0x02000000,
+ SupervisorCall = 0x04000000,
+ InstructionBreakpoint = 0x08000000,
+ PrefetchAbort = 0x20000000,
+};
+DECLARE_ENUM_FLAG_OPERATORS(HaltReason);
+
+enum class Architecture {
+ Aarch32,
+ Aarch64,
+};
+
/// Generic ARMv8 CPU interface
class ARM_Interface {
public:
@@ -167,8 +181,9 @@ public:
*/
virtual void SetTPIDR_EL0(u64 value) = 0;
- virtual void SaveContext(ThreadContext32& ctx) = 0;
- virtual void SaveContext(ThreadContext64& ctx) = 0;
+ virtual Architecture GetArchitecture() const = 0;
+ virtual void SaveContext(ThreadContext32& ctx) const = 0;
+ virtual void SaveContext(ThreadContext64& ctx) const = 0;
virtual void LoadContext(const ThreadContext32& ctx) = 0;
virtual void LoadContext(const ThreadContext64& ctx) = 0;
void LoadWatchpointArray(const WatchpointArray& wp);
@@ -195,17 +210,9 @@ public:
static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
const ThreadContext64& ctx);
- virtual std::vector<BacktraceEntry> GetBacktrace() const = 0;
-
+ std::vector<BacktraceEntry> GetBacktrace() const;
void LogBacktrace() const;
- static constexpr Dynarmic::HaltReason step_thread = Dynarmic::HaltReason::Step;
- static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
- static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
- static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4;
- static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::MemoryAbort;
- static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6;
-
protected:
/// System context that this ARM interface is running under.
System& system;
@@ -216,8 +223,8 @@ protected:
const Kernel::DebugWatchpoint* MatchingWatchpoint(
u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const;
- virtual Dynarmic::HaltReason RunJit() = 0;
- virtual Dynarmic::HaltReason StepJit() = 0;
+ virtual HaltReason RunJit() = 0;
+ virtual HaltReason StepJit() = 0;
virtual u32 GetSvcNumber() const = 0;
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
virtual void RewindBreakpointInstruction() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
new file mode 100644
index 000000000..eef7c3116
--- /dev/null
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <dynarmic/interface/halt_reason.h>
+
+#include "core/arm/arm_interface.h"
+
+namespace Core {
+
+constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
+constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
+constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
+constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
+constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
+constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
+
+constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
+ static_assert(static_cast<u64>(HaltReason::StepThread) == static_cast<u64>(StepThread));
+ static_assert(static_cast<u64>(HaltReason::DataAbort) == static_cast<u64>(DataAbort));
+ static_assert(static_cast<u64>(HaltReason::BreakLoop) == static_cast<u64>(BreakLoop));
+ static_assert(static_cast<u64>(HaltReason::SupervisorCall) == static_cast<u64>(SupervisorCall));
+ static_assert(static_cast<u64>(HaltReason::InstructionBreakpoint) ==
+ static_cast<u64>(InstructionBreakpoint));
+ static_assert(static_cast<u64>(HaltReason::PrefetchAbort) == static_cast<u64>(PrefetchAbort));
+
+ return static_cast<HaltReason>(hr);
+}
+
+} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index dfdcbe35a..5acf9008d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -10,9 +10,10 @@
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
+#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
-#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_cp15.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/debugger/debugger.h"
@@ -104,11 +105,11 @@ public:
switch (exception) {
case Dynarmic::A32::Exception::NoExecuteFault:
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc);
- ReturnException(pc, ARM_Interface::no_execute);
+ ReturnException(pc, PrefetchAbort);
return;
default:
if (debugger_enabled) {
- ReturnException(pc, ARM_Interface::breakpoint);
+ ReturnException(pc, InstructionBreakpoint);
return;
}
@@ -121,7 +122,7 @@ public:
void CallSVC(u32 swi) override {
parent.svc_swi = swi;
- parent.jit.load()->HaltExecution(ARM_Interface::svc_call);
+ parent.jit.load()->HaltExecution(SupervisorCall);
}
void AddTicks(u64 ticks) override {
@@ -162,7 +163,7 @@ public:
if (!memory.IsValidVirtualAddressRange(addr, size)) {
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
addr);
- parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
+ parent.jit.load()->HaltExecution(PrefetchAbort);
return false;
}
@@ -173,7 +174,7 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.halted_watchpoint = match;
- parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
+ parent.jit.load()->HaltExecution(DataAbort);
return false;
}
@@ -329,12 +330,12 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
return std::make_unique<Dynarmic::A32::Jit>(config);
}
-Dynarmic::HaltReason ARM_Dynarmic_32::RunJit() {
- return jit.load()->Run();
+HaltReason ARM_Dynarmic_32::RunJit() {
+ return TranslateHaltReason(jit.load()->Run());
}
-Dynarmic::HaltReason ARM_Dynarmic_32::StepJit() {
- return jit.load()->Step();
+HaltReason ARM_Dynarmic_32::StepJit() {
+ return TranslateHaltReason(jit.load()->Step());
}
u32 ARM_Dynarmic_32::GetSvcNumber() const {
@@ -408,7 +409,7 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
cp15->uprw = static_cast<u32>(value);
}
-void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
+void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) const {
Dynarmic::A32::Jit* j = jit.load();
ctx.cpu_registers = j->Regs();
ctx.extension_registers = j->ExtRegs();
@@ -425,11 +426,11 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
}
void ARM_Dynarmic_32::SignalInterrupt() {
- jit.load()->HaltExecution(break_loop);
+ jit.load()->HaltExecution(BreakLoop);
}
void ARM_Dynarmic_32::ClearInterrupt() {
- jit.load()->ClearHalt(break_loop);
+ jit.load()->ClearHalt(BreakLoop);
}
void ARM_Dynarmic_32::ClearInstructionCache() {
@@ -462,39 +463,4 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
jit_cache.emplace(key, std::move(new_jit));
}
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system,
- u64 fp, u64 lr, u64 pc) {
- std::vector<BacktraceEntry> out;
- auto& memory = system.ApplicationMemory();
-
- out.push_back({"", 0, pc, 0, ""});
-
- // fp (= r11) points to the last frame record.
- // Frame records are two words long:
- // fp+0 : pointer to previous frame record
- // fp+4 : value of lr for frame
- for (size_t i = 0; i < 256; i++) {
- out.push_back({"", 0, lr, 0, ""});
- if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
- break;
- }
- lr = memory.Read32(fp + 4);
- fp = memory.Read32(fp);
- }
-
- SymbolicateBacktrace(system, out);
-
- return out;
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext(
- System& system, const ThreadContext32& ctx) {
- const auto& reg = ctx.cpu_registers;
- return GetBacktrace(system, reg[11], reg[14], reg[15]);
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const {
- return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15));
-}
-
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index bce695daf..a990845cb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -50,8 +50,11 @@ public:
return (GetPSTATE() & 0x20) != 0;
}
- void SaveContext(ThreadContext32& ctx) override;
- void SaveContext(ThreadContext64& ctx) override {}
+ Architecture GetArchitecture() const override {
+ return Architecture::Aarch32;
+ }
+ void SaveContext(ThreadContext32& ctx) const override;
+ void SaveContext(ThreadContext64& ctx) const override {}
void LoadContext(const ThreadContext32& ctx) override;
void LoadContext(const ThreadContext64& ctx) override {}
@@ -64,14 +67,9 @@ public:
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
- static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
- const ThreadContext32& ctx);
-
- std::vector<BacktraceEntry> GetBacktrace() const override;
-
protected:
- Dynarmic::HaltReason RunJit() override;
- Dynarmic::HaltReason StepJit() override;
+ HaltReason RunJit() override;
+ HaltReason StepJit() override;
u32 GetSvcNumber() const override;
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
void RewindBreakpointInstruction() override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index bbbcb4f9d..bb97ed5bc 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -10,8 +10,9 @@
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
+#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/debugger/debugger.h"
@@ -113,7 +114,7 @@ public:
LOG_ERROR(Core_ARM,
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, memory.Read32(pc));
- ReturnException(pc, ARM_Interface::no_execute);
+ ReturnException(pc, PrefetchAbort);
}
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
@@ -148,11 +149,11 @@ public:
return;
case Dynarmic::A64::Exception::NoExecuteFault:
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc);
- ReturnException(pc, ARM_Interface::no_execute);
+ ReturnException(pc, PrefetchAbort);
return;
default:
if (debugger_enabled) {
- ReturnException(pc, ARM_Interface::breakpoint);
+ ReturnException(pc, InstructionBreakpoint);
return;
}
@@ -164,7 +165,7 @@ public:
void CallSVC(u32 swi) override {
parent.svc_swi = swi;
- parent.jit.load()->HaltExecution(ARM_Interface::svc_call);
+ parent.jit.load()->HaltExecution(SupervisorCall);
}
void AddTicks(u64 ticks) override {
@@ -207,7 +208,7 @@ public:
if (!memory.IsValidVirtualAddressRange(addr, size)) {
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
addr);
- parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
+ parent.jit.load()->HaltExecution(PrefetchAbort);
return false;
}
@@ -218,7 +219,7 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.halted_watchpoint = match;
- parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
+ parent.jit.load()->HaltExecution(DataAbort);
return false;
}
@@ -383,12 +384,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
return std::make_shared<Dynarmic::A64::Jit>(config);
}
-Dynarmic::HaltReason ARM_Dynarmic_64::RunJit() {
- return jit.load()->Run();
+HaltReason ARM_Dynarmic_64::RunJit() {
+ return TranslateHaltReason(jit.load()->Run());
}
-Dynarmic::HaltReason ARM_Dynarmic_64::StepJit() {
- return jit.load()->Step();
+HaltReason ARM_Dynarmic_64::StepJit() {
+ return TranslateHaltReason(jit.load()->Step());
}
u32 ARM_Dynarmic_64::GetSvcNumber() const {
@@ -464,7 +465,7 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) {
cb->tpidr_el0 = value;
}
-void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
+void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) const {
Dynarmic::A64::Jit* j = jit.load();
ctx.cpu_registers = j->GetRegisters();
ctx.sp = j->GetSP();
@@ -489,11 +490,11 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
}
void ARM_Dynarmic_64::SignalInterrupt() {
- jit.load()->HaltExecution(break_loop);
+ jit.load()->HaltExecution(BreakLoop);
}
void ARM_Dynarmic_64::ClearInterrupt() {
- jit.load()->ClearHalt(break_loop);
+ jit.load()->ClearHalt(BreakLoop);
}
void ARM_Dynarmic_64::ClearInstructionCache() {
@@ -526,39 +527,4 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
jit_cache.emplace(key, std::move(new_jit));
}
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system,
- u64 fp, u64 lr, u64 pc) {
- std::vector<BacktraceEntry> out;
- auto& memory = system.ApplicationMemory();
-
- out.push_back({"", 0, pc, 0, ""});
-
- // fp (= x29) points to the previous frame record.
- // Frame records are two words long:
- // fp+0 : pointer to previous frame record
- // fp+8 : value of lr for frame
- for (size_t i = 0; i < 256; i++) {
- out.push_back({"", 0, lr, 0, ""});
- if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
- break;
- }
- lr = memory.Read64(fp + 8);
- fp = memory.Read64(fp);
- }
-
- SymbolicateBacktrace(system, out);
-
- return out;
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext(
- System& system, const ThreadContext64& ctx) {
- const auto& reg = ctx.cpu_registers;
- return GetBacktrace(system, reg[29], reg[30], ctx.pc);
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const {
- return GetBacktrace(system, GetReg(29), GetReg(30), GetPC());
-}
-
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index e83599e82..af2aa1f1c 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -43,8 +43,11 @@ public:
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
- void SaveContext(ThreadContext32& ctx) override {}
- void SaveContext(ThreadContext64& ctx) override;
+ Architecture GetArchitecture() const override {
+ return Architecture::Aarch64;
+ }
+ void SaveContext(ThreadContext32& ctx) const override {}
+ void SaveContext(ThreadContext64& ctx) const override;
void LoadContext(const ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext64& ctx) override;
@@ -57,14 +60,9 @@ public:
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
- static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
- const ThreadContext64& ctx);
-
- std::vector<BacktraceEntry> GetBacktrace() const override;
-
protected:
- Dynarmic::HaltReason RunJit() override;
- Dynarmic::HaltReason StepJit() override;
+ HaltReason RunJit() override;
+ HaltReason StepJit() override;
u32 GetSvcNumber() const override;
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
void RewindBreakpointInstruction() override;
@@ -73,8 +71,6 @@ private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
- static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
-
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/dynarmic_cp15.cpp
index 5a4eba3eb..92c548db0 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/dynarmic_cp15.cpp
@@ -4,7 +4,7 @@
#include <fmt/format.h>
#include "common/logging/log.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
-#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
+#include "core/arm/dynarmic/dynarmic_cp15.h"
#include "core/core.h"
#include "core/core_timing.h"
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/dynarmic_cp15.h
index d90b3e568..d90b3e568 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/dynarmic_cp15.h
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.cpp
index fa0c48b25..b5c9c43c4 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
+++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.cpp
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/memory.h"
namespace Core {
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
index 57e6dd0d0..57e6dd0d0 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
diff --git a/src/core/arm/exclusive_monitor.cpp b/src/core/arm/exclusive_monitor.cpp
index 20550faeb..6d9a862e1 100644
--- a/src/core/arm/exclusive_monitor.cpp
+++ b/src/core/arm/exclusive_monitor.cpp
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#endif
#include "core/arm/exclusive_monitor.h"
#include "core/memory.h"
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 4406ae30e..b74fd0a58 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -54,10 +54,10 @@
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU0, "ARM JIT", "Dynarmic CPU 0", MP_RGB(255, 64, 64));
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU1, "ARM JIT", "Dynarmic CPU 1", MP_RGB(255, 64, 64));
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU2, "ARM JIT", "Dynarmic CPU 2", MP_RGB(255, 64, 64));
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU3, "ARM JIT", "Dynarmic CPU 3", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU0, "ARM", "CPU 0", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU1, "ARM", "CPU 1", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU2, "ARM", "CPU 2", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU3, "ARM", "CPU 3", MP_RGB(255, 64, 64));
namespace Core {
@@ -216,6 +216,14 @@ struct System::Impl {
}
}
+ void SetNVDECActive(bool is_nvdec_active) {
+ nvdec_active = is_nvdec_active;
+ }
+
+ bool GetNVDECActive() {
+ return nvdec_active;
+ }
+
void InitializeDebugger(System& system, u16 port) {
debugger = std::make_unique<Debugger>(system, port);
}
@@ -251,10 +259,10 @@ struct System::Impl {
is_powered_on = true;
exit_lock = false;
- microprofile_dynarmic[0] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU0);
- microprofile_dynarmic[1] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU1);
- microprofile_dynarmic[2] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU2);
- microprofile_dynarmic[3] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU3);
+ microprofile_cpu[0] = MICROPROFILE_TOKEN(ARM_CPU0);
+ microprofile_cpu[1] = MICROPROFILE_TOKEN(ARM_CPU1);
+ microprofile_cpu[2] = MICROPROFILE_TOKEN(ARM_CPU2);
+ microprofile_cpu[3] = MICROPROFILE_TOKEN(ARM_CPU3);
LOG_DEBUG(Core, "Initialized OK");
@@ -485,6 +493,8 @@ struct System::Impl {
std::atomic_bool is_powered_on{};
bool exit_lock = false;
+ bool nvdec_active{};
+
Reporter reporter;
std::unique_ptr<Memory::CheatEngine> cheat_engine;
std::unique_ptr<Tools::Freezer> memory_freezer;
@@ -529,7 +539,7 @@ struct System::Impl {
ExitCallback exit_callback;
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
- std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
+ std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
};
System::System() : impl{std::make_unique<Impl>(*this)} {}
@@ -594,6 +604,14 @@ void System::UnstallApplication() {
impl->UnstallApplication();
}
+void System::SetNVDECActive(bool is_nvdec_active) {
+ impl->SetNVDECActive(is_nvdec_active);
+}
+
+bool System::GetNVDECActive() {
+ return impl->GetNVDECActive();
+}
+
void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
}
@@ -909,14 +927,14 @@ void System::RegisterHostThread() {
impl->kernel.RegisterHostThread();
}
-void System::EnterDynarmicProfile() {
+void System::EnterCPUProfile() {
std::size_t core = impl->kernel.GetCurrentHostThreadID();
- impl->dynarmic_ticks[core] = MicroProfileEnter(impl->microprofile_dynarmic[core]);
+ impl->dynarmic_ticks[core] = MicroProfileEnter(impl->microprofile_cpu[core]);
}
-void System::ExitDynarmicProfile() {
+void System::ExitCPUProfile() {
std::size_t core = impl->kernel.GetCurrentHostThreadID();
- MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]);
+ MicroProfileLeave(impl->microprofile_cpu[core], impl->dynarmic_ticks[core]);
}
bool System::IsMulticore() const {
diff --git a/src/core/core.h b/src/core/core.h
index 4f153154f..93afc9303 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -189,6 +189,9 @@ public:
std::unique_lock<std::mutex> StallApplication();
void UnstallApplication();
+ void SetNVDECActive(bool is_nvdec_active);
+ [[nodiscard]] bool GetNVDECActive();
+
/**
* Initialize the debugger.
*/
@@ -409,11 +412,11 @@ public:
/// Register a host thread as an auxiliary thread.
void RegisterHostThread();
- /// Enter Dynarmic Microprofile
- void EnterDynarmicProfile();
+ /// Enter CPU Microprofile
+ void EnterCPUProfile();
- /// Exit Dynarmic Microprofile
- void ExitDynarmicProfile();
+ /// Exit CPU Microprofile
+ void ExitCPUProfile();
/// Tells if system is running on multicore.
[[nodiscard]] bool IsMulticore() const;
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 65a9fe802..4ff2c50e5 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -569,6 +569,10 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
}
KeyManager::KeyManager() {
+ ReloadKeys();
+}
+
+void KeyManager::ReloadKeys() {
// Initialize keys
const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
@@ -702,6 +706,10 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
}
}
+bool KeyManager::AreKeysLoaded() const {
+ return !s128_keys.empty() && !s256_keys.empty();
+}
+
bool KeyManager::BaseDeriveNecessary() const {
const auto check_key_existence = [this](auto key_type, u64 index1 = 0, u64 index2 = 0) {
return !HasKey(key_type, index1, index2);
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index 673cec463..8c864503b 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -267,6 +267,9 @@ public:
bool AddTicketCommon(Ticket raw);
bool AddTicketPersonalized(Ticket raw);
+ void ReloadKeys();
+ bool AreKeysLoaded() const;
+
private:
KeyManager();
diff --git a/src/core/device_memory.cpp b/src/core/device_memory.cpp
index f8b5be2b4..de3f8ef8f 100644
--- a/src/core/device_memory.cpp
+++ b/src/core/device_memory.cpp
@@ -6,9 +6,15 @@
namespace Core {
+#ifdef ANDROID
+constexpr size_t VirtualReserveSize = 1ULL << 38;
+#else
+constexpr size_t VirtualReserveSize = 1ULL << 39;
+#endif
+
DeviceMemory::DeviceMemory()
: buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(),
- 1ULL << 39} {}
+ VirtualReserveSize} {}
DeviceMemory::~DeviceMemory() = default;
} // namespace Core
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 50f44f598..cd9ac2e75 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -23,8 +23,8 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{
"Portuguese",
"Russian",
"Korean",
- "Taiwanese",
- "Chinese",
+ "TraditionalChinese",
+ "SimplifiedChinese",
"BrazilianPortuguese",
}};
@@ -45,17 +45,17 @@ constexpr std::array<Language, 18> language_to_codes = {{
Language::German,
Language::Italian,
Language::Spanish,
- Language::Chinese,
+ Language::SimplifiedChinese,
Language::Korean,
Language::Dutch,
Language::Portuguese,
Language::Russian,
- Language::Taiwanese,
+ Language::TraditionalChinese,
Language::BritishEnglish,
Language::CanadianFrench,
Language::LatinAmericanSpanish,
- Language::Chinese,
- Language::Taiwanese,
+ Language::SimplifiedChinese,
+ Language::TraditionalChinese,
Language::BrazilianPortuguese,
}};
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 6a81873b1..c98efb00d 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -84,8 +84,8 @@ enum class Language : u8 {
Portuguese = 10,
Russian = 11,
Korean = 12,
- Taiwanese = 13,
- Chinese = 14,
+ TraditionalChinese = 13,
+ SimplifiedChinese = 14,
BrazilianPortuguese = 15,
Default = 255,
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index f786f2add..4e61d4335 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -25,6 +25,8 @@
#include "core/file_sys/vfs_layered.h"
#include "core/file_sys/vfs_vector.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/ns/language.h"
+#include "core/hle/service/set/set.h"
#include "core/loader/loader.h"
#include "core/loader/nso.h"
#include "core/memory/cheat_engine.h"
@@ -624,8 +626,37 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
+ // Get language code from settings
+ const auto language_code =
+ Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
+
+ // Convert to application language and get priority list
+ const auto application_language =
+ Service::NS::ConvertToApplicationLanguage(language_code)
+ .value_or(Service::NS::ApplicationLanguage::AmericanEnglish);
+ const auto language_priority_list =
+ Service::NS::GetApplicationLanguagePriorityList(application_language);
+
+ // Convert to language names
+ auto priority_language_names = FileSys::LANGUAGE_NAMES; // Copy
+ if (language_priority_list) {
+ for (size_t i = 0; i < priority_language_names.size(); ++i) {
+ // Relies on FileSys::LANGUAGE_NAMES being in the same order as
+ // Service::NS::ApplicationLanguage
+ const auto language_index = static_cast<u8>(language_priority_list->at(i));
+
+ if (language_index < FileSys::LANGUAGE_NAMES.size()) {
+ priority_language_names[i] = FileSys::LANGUAGE_NAMES[language_index];
+ } else {
+ // Not a catastrophe, unlikely to happen
+ LOG_WARNING(Loader, "Invalid language index {}", language_index);
+ }
+ }
+ }
+
+ // Get first matching icon
VirtualFile icon_file;
- for (const auto& language : FileSys::LANGUAGE_NAMES) {
+ for (const auto& language : priority_language_names) {
icon_file = extracted->GetFile(std::string("icon_").append(language).append(".dat"));
if (icon_file != nullptr) {
break;
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 3226b884a..27f97c725 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -8,6 +8,7 @@
#include <set>
#include <vector>
#include "common/common_types.h"
+#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/vfs.h"
namespace Core::Crypto {
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 1be2dccb0..d1f1ca8c9 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -6,8 +6,6 @@
namespace Core::Frontend {
-GraphicsContext::~GraphicsContext() = default;
-
EmuWindow::EmuWindow() {
// TODO: Find a better place to set this.
config.min_client_area_size =
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 1093800f6..a72df034e 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -5,11 +5,14 @@
#include <memory>
#include <utility>
+
#include "common/common_types.h"
#include "core/frontend/framebuffer_layout.h"
namespace Core::Frontend {
+class GraphicsContext;
+
/// Information for the Graphics Backends signifying what type of screen pointer is in
/// WindowInformation
enum class WindowSystemType {
@@ -22,51 +25,6 @@ enum class WindowSystemType {
};
/**
- * Represents a drawing context that supports graphics operations.
- */
-class GraphicsContext {
-public:
- virtual ~GraphicsContext();
-
- /// Inform the driver to swap the front/back buffers and present the current image
- virtual void SwapBuffers() {}
-
- /// Makes the graphics context current for the caller thread
- virtual void MakeCurrent() {}
-
- /// Releases (dunno if this is the "right" word) the context from the caller thread
- virtual void DoneCurrent() {}
-
- class Scoped {
- public:
- [[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
- context.MakeCurrent();
- }
- ~Scoped() {
- if (active) {
- context.DoneCurrent();
- }
- }
-
- /// In the event that context was destroyed before the Scoped is destroyed, this provides a
- /// mechanism to prevent calling a destroyed object's method during the deconstructor
- void Cancel() {
- active = false;
- }
-
- private:
- GraphicsContext& context;
- bool active{true};
- };
-
- /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
- /// ends
- [[nodiscard]] Scoped Acquire() {
- return Scoped{*this};
- }
-};
-
-/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
*
diff --git a/src/core/frontend/graphics_context.h b/src/core/frontend/graphics_context.h
new file mode 100644
index 000000000..7554c1583
--- /dev/null
+++ b/src/core/frontend/graphics_context.h
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <memory>
+
+#include "common/dynamic_library.h"
+
+namespace Core::Frontend {
+
+/**
+ * Represents a drawing context that supports graphics operations.
+ */
+class GraphicsContext {
+public:
+ virtual ~GraphicsContext() = default;
+
+ /// Inform the driver to swap the front/back buffers and present the current image
+ virtual void SwapBuffers() {}
+
+ /// Makes the graphics context current for the caller thread
+ virtual void MakeCurrent() {}
+
+ /// Releases (dunno if this is the "right" word) the context from the caller thread
+ virtual void DoneCurrent() {}
+
+ /// Gets the GPU driver library (used by Android only)
+ virtual std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() {
+ return {};
+ }
+
+ class Scoped {
+ public:
+ [[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
+ context.MakeCurrent();
+ }
+ ~Scoped() {
+ if (active) {
+ context.DoneCurrent();
+ }
+ }
+
+ /// In the event that context was destroyed before the Scoped is destroyed, this provides a
+ /// mechanism to prevent calling a destroyed object's method during the deconstructor
+ void Cancel() {
+ active = false;
+ }
+
+ private:
+ GraphicsContext& context;
+ bool active{true};
+ };
+
+ /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
+ /// ends
+ [[nodiscard]] Scoped Acquire() {
+ return Scoped{*this};
+ }
+};
+
+} // namespace Core::Frontend
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index 17d663379..b4afd930e 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -13,7 +13,7 @@ EmulatedConsole::~EmulatedConsole() = default;
void EmulatedConsole::ReloadFromSettings() {
// Using first motion device from player 1. No need to assign any unique config at the moment
const auto& player = Settings::values.players.GetValue()[0];
- motion_params = Common::ParamPackage(player.motions[0]);
+ motion_params[0] = Common::ParamPackage(player.motions[0]);
ReloadInput();
}
@@ -74,14 +74,30 @@ void EmulatedConsole::ReloadInput() {
// If you load any device here add the equivalent to the UnloadInput() function
SetTouchParams();
- motion_devices = Common::Input::CreateInputDevice(motion_params);
- if (motion_devices) {
- motion_devices->SetCallback({
+ motion_params[1] = Common::ParamPackage{"engine:virtual_gamepad,port:8,motion:0"};
+
+ for (std::size_t index = 0; index < motion_devices.size(); ++index) {
+ motion_devices[index] = Common::Input::CreateInputDevice(motion_params[index]);
+ if (!motion_devices[index]) {
+ continue;
+ }
+ motion_devices[index]->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
});
}
+ // Restore motion state
+ auto& emulated_motion = console.motion_values.emulated;
+ auto& motion = console.motion_state;
+ emulated_motion.ResetRotations();
+ emulated_motion.ResetQuaternion();
+ motion.accel = emulated_motion.GetAcceleration();
+ motion.gyro = emulated_motion.GetGyroscope();
+ motion.rotation = emulated_motion.GetRotations();
+ motion.orientation = emulated_motion.GetOrientation();
+ motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
+
// Unique index for identifying touch device source
std::size_t index = 0;
for (auto& touch_device : touch_devices) {
@@ -100,7 +116,9 @@ void EmulatedConsole::ReloadInput() {
}
void EmulatedConsole::UnloadInput() {
- motion_devices.reset();
+ for (auto& motion : motion_devices) {
+ motion.reset();
+ }
for (auto& touch : touch_devices) {
touch.reset();
}
@@ -133,11 +151,11 @@ void EmulatedConsole::RestoreConfig() {
}
Common::ParamPackage EmulatedConsole::GetMotionParam() const {
- return motion_params;
+ return motion_params[0];
}
void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
- motion_params = std::move(param);
+ motion_params[0] = std::move(param);
ReloadInput();
}
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index 697ecd2d6..79114bb6d 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -29,10 +29,10 @@ struct ConsoleMotionInfo {
MotionInput emulated{};
};
-using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>;
+using ConsoleMotionDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 2>;
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
-using ConsoleMotionParams = Common::ParamPackage;
+using ConsoleMotionParams = std::array<Common::ParamPackage, 2>;
using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
using ConsoleMotionValues = ConsoleMotionInfo;
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index bbfea7117..0a7777732 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -193,6 +193,8 @@ void EmulatedController::LoadDevices() {
Common::Input::CreateInputDevice);
std::ranges::transform(virtual_stick_params, virtual_stick_devices.begin(),
Common::Input::CreateInputDevice);
+ std::ranges::transform(virtual_motion_params, virtual_motion_devices.begin(),
+ Common::Input::CreateInputDevice);
}
void EmulatedController::LoadTASParams() {
@@ -253,6 +255,12 @@ void EmulatedController::LoadVirtualGamepadParams() {
for (auto& param : virtual_stick_params) {
param = common_params;
}
+ for (auto& param : virtual_stick_params) {
+ param = common_params;
+ }
+ for (auto& param : virtual_motion_params) {
+ param = common_params;
+ }
// TODO(german77): Replace this with an input profile or something better
virtual_button_params[Settings::NativeButton::A].Set("button", 0);
@@ -284,6 +292,9 @@ void EmulatedController::LoadVirtualGamepadParams() {
virtual_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f);
virtual_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f);
virtual_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f);
+
+ virtual_motion_params[Settings::NativeMotion::MotionLeft].Set("motion", 0);
+ virtual_motion_params[Settings::NativeMotion::MotionRight].Set("motion", 0);
}
void EmulatedController::ReloadInput() {
@@ -463,6 +474,18 @@ void EmulatedController::ReloadInput() {
},
});
}
+
+ for (std::size_t index = 0; index < virtual_motion_devices.size(); ++index) {
+ if (!virtual_motion_devices[index]) {
+ continue;
+ }
+ virtual_motion_devices[index]->SetCallback({
+ .on_change =
+ [this, index](const Common::Input::CallbackStatus& callback) {
+ SetMotion(callback, index);
+ },
+ });
+ }
turbo_button_state = 0;
}
@@ -500,6 +523,9 @@ void EmulatedController::UnloadInput() {
for (auto& stick : virtual_stick_devices) {
stick.reset();
}
+ for (auto& motion : virtual_motion_devices) {
+ motion.reset();
+ }
for (auto& camera : camera_devices) {
camera.reset();
}
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 88fad2f56..09fe1a0ab 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -568,8 +568,10 @@ private:
// Virtual gamepad related variables
ButtonParams virtual_button_params;
StickParams virtual_stick_params;
+ ControllerMotionParams virtual_motion_params;
ButtonDevices virtual_button_devices;
StickDevices virtual_stick_devices;
+ ControllerMotionDevices virtual_motion_devices;
mutable std::mutex mutex;
mutable std::mutex callback_mutex;
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp
index c36eb5dc4..32173e52b 100644
--- a/src/core/hle/kernel/k_address_space_info.cpp
+++ b/src/core/hle/kernel/k_address_space_info.cpp
@@ -25,7 +25,12 @@ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
+#ifdef ANDROID
+ // With Android, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region.
+ { .bit_width = 39, .address = 128_MiB , .size = 256_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
+#else
{ .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
+#endif
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, },
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 63fd5bfd6..5542d6cbc 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -46,6 +46,7 @@ ProfileManager::ProfileManager() {
// Create an user if none are present
if (user_count == 0) {
CreateNewUser(UUID::MakeRandom(), "yuzu");
+ WriteUserSaveFile();
}
auto current =
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 0bd7900e1..b14f682b5 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -12,6 +12,11 @@
#pragma warning(pop)
#endif
+#include <fmt/format.h>
+
+#include "common/fs/file.h"
+#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
#include "common/input.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -136,7 +141,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
LOG_INFO(Service_NFC, "Loading amiibo without keys");
memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
- BuildAmiiboWithoutKeys();
+ BuildAmiiboWithoutKeys(tag_data, encrypted_tag_data);
is_plain_amiibo = true;
is_write_protected = true;
return true;
@@ -366,16 +371,25 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
// The loaded amiibo is not encrypted
if (is_plain_amiibo) {
+ std::vector<u8> data(sizeof(NFP::NTAG215File));
+ memcpy(data.data(), &tag_data, sizeof(tag_data));
+ WriteBackupData(tag_data.uid, data);
+
device_state = DeviceState::TagMounted;
mount_target = mount_target_;
return ResultSuccess;
}
if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
- LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
- return ResultCorruptedData;
+ bool has_backup = HasBackup(encrypted_tag_data.uuid.uid).IsSuccess();
+ LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
+ return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
}
+ std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
+ memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
+ WriteBackupData(encrypted_tag_data.uuid.uid, data);
+
device_state = DeviceState::TagMounted;
mount_target = mount_target_;
return ResultSuccess;
@@ -470,6 +484,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
if (is_plain_amiibo) {
memcpy(data.data(), &tag_data, sizeof(tag_data));
+ WriteBackupData(tag_data.uid, data);
} else {
if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
LOG_ERROR(Service_NFP, "Failed to encode data");
@@ -477,6 +492,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
}
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
+ WriteBackupData(encrypted_tag_data.uuid.uid, data);
}
if (!npad_device->WriteNfc(data)) {
@@ -488,7 +504,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
}
Result NfcDevice::Restore() {
- if (device_state != DeviceState::TagMounted) {
+ if (device_state != DeviceState::TagFound) {
LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
if (device_state == DeviceState::TagRemoved) {
return ResultTagRemoved;
@@ -496,13 +512,59 @@ Result NfcDevice::Restore() {
return ResultWrongDeviceState;
}
- if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
- LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
- return ResultWrongDeviceState;
+ NFC::TagInfo tag_info{};
+ std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
+ Result result = GetTagInfo(tag_info, false);
+
+ if (result.IsError()) {
+ return result;
}
- // TODO: Load amiibo from backup on system
- LOG_ERROR(Service_NFP, "Not Implemented");
+ result = ReadBackupData(tag_info.uuid, data);
+
+ if (result.IsError()) {
+ return result;
+ }
+
+ NFP::NTAG215File temporary_tag_data{};
+ NFP::EncryptedNTAG215File temporary_encrypted_tag_data{};
+
+ // Fallback for encrypted amiibos without keys
+ if (is_write_protected) {
+ return ResultWriteAmiiboFailed;
+ }
+
+ // Fallback for plain amiibos
+ if (is_plain_amiibo) {
+ LOG_INFO(Service_NFP, "Restoring backup of plain amiibo");
+ memcpy(&temporary_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+ temporary_encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(temporary_tag_data);
+ }
+
+ if (!is_plain_amiibo) {
+ LOG_INFO(Service_NFP, "Restoring backup of encrypted amiibo");
+ temporary_tag_data = {};
+ memcpy(&temporary_encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+ }
+
+ if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
+ return ResultNotAnAmiibo;
+ }
+
+ if (!is_plain_amiibo) {
+ if (!NFP::AmiiboCrypto::DecodeAmiibo(temporary_encrypted_tag_data, temporary_tag_data)) {
+ LOG_ERROR(Service_NFP, "Can't decode amiibo");
+ return ResultCorruptedData;
+ }
+ }
+
+ // Overwrite tag contents with backup and mount the tag
+ tag_data = temporary_tag_data;
+ encrypted_tag_data = temporary_encrypted_tag_data;
+ device_state = DeviceState::TagMounted;
+ mount_target = NFP::MountTarget::All;
+ is_data_moddified = true;
+
return ResultSuccess;
}
@@ -1132,13 +1194,69 @@ Result NfcDevice::BreakTag(NFP::BreakType break_type) {
return FlushWithBreak(break_type);
}
-Result NfcDevice::ReadBackupData(std::span<u8> data) const {
- // Not implemented
+Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
+ constexpr auto backup_dir = "backup";
+ const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+ const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
+
+ if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
+ return ResultUnableToAccessBackupFile;
+ }
+
return ResultSuccess;
}
-Result NfcDevice::WriteBackupData(std::span<const u8> data) {
- // Not implemented
+Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const {
+ constexpr auto backup_dir = "backup";
+ const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+ const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
+
+ const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
+ Common::FS::FileAccessMode::Read,
+ Common::FS::FileType::BinaryFile};
+
+ if (!keys_file.IsOpen()) {
+ LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
+ if (keys_file.Read(data) != data.size()) {
+ LOG_ERROR(Service_NFP, "Failed to read amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data) {
+ constexpr auto backup_dir = "backup";
+ const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+ const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
+
+ if (HasBackup(uid).IsError()) {
+ if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
+ return ResultBackupPathAlreadyExist;
+ }
+
+ if (!Common::FS::NewFile(yuzu_amiibo_dir / backup_dir / file_name)) {
+ return ResultBackupPathAlreadyExist;
+ }
+ }
+
+ const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
+ Common::FS::FileAccessMode::ReadWrite,
+ Common::FS::FileType::BinaryFile};
+
+ if (!keys_file.IsOpen()) {
+ LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
+ if (keys_file.Write(data) != data.size()) {
+ LOG_ERROR(Service_NFP, "Failed to write amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
return ResultSuccess;
}
@@ -1177,7 +1295,8 @@ NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) co
return amiibo_name;
}
-void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) {
+void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
+ const NFP::AmiiboName& amiibo_name) const {
std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
// Convert from utf8 to utf16
@@ -1258,22 +1377,23 @@ void NfcDevice::UpdateRegisterInfoCrc() {
tag_data.register_info_crc = crc.checksum();
}
-void NfcDevice::BuildAmiiboWithoutKeys() {
+void NfcDevice::BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
+ const NFP::EncryptedNTAG215File& encrypted_file) const {
Service::Mii::MiiManager manager;
- auto& settings = tag_data.settings;
+ auto& settings = stubbed_tag_data.settings;
- tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_tag_data);
+ stubbed_tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_file);
// Common info
- tag_data.write_counter = 0;
- tag_data.amiibo_version = 0;
+ stubbed_tag_data.write_counter = 0;
+ stubbed_tag_data.amiibo_version = 0;
settings.write_date = GetAmiiboDate(GetCurrentPosixTime());
// Register info
SetAmiiboName(settings, {'y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o'});
settings.settings.font_region.Assign(0);
settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
- tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
+ stubbed_tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
// Admin info
settings.settings.amiibo_initialized.Assign(1);
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 6a37e8458..6f049b687 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -86,8 +86,9 @@ public:
Result GetAll(NFP::NfpData& data) const;
Result SetAll(const NFP::NfpData& data);
Result BreakTag(NFP::BreakType break_type);
- Result ReadBackupData(std::span<u8> data) const;
- Result WriteBackupData(std::span<const u8> data);
+ Result HasBackup(const NFC::UniqueSerialNumber& uid) const;
+ Result ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const;
+ Result WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data);
Result WriteNtf(std::span<const u8> data);
u64 GetHandle() const;
@@ -103,14 +104,15 @@ private:
void CloseNfcTag();
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
- void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
+ void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const;
NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
u64 GetCurrentPosixTime() const;
u64 RemoveVersionByte(u64 application_id) const;
void UpdateSettingsCrc();
void UpdateRegisterInfoCrc();
- void BuildAmiiboWithoutKeys();
+ void BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
+ const NFP::EncryptedNTAG215File& encrypted_file) const;
bool is_controller_set{};
int callback_key;
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index d5deaaf27..cffd602df 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -543,9 +543,14 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
+ NFC::TagInfo tag_info{};
if (result.IsSuccess()) {
- result = device->ReadBackupData(data);
+ result = device->GetTagInfo(tag_info, false);
+ }
+
+ if (result.IsSuccess()) {
+ result = device->ReadBackupData(tag_info.uuid, data);
result = VerifyDeviceResult(device, result);
}
@@ -557,9 +562,14 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
+ NFC::TagInfo tag_info{};
+
+ if (result.IsSuccess()) {
+ result = device->GetTagInfo(tag_info, false);
+ }
if (result.IsSuccess()) {
- result = device->WriteBackupData(data);
+ result = device->WriteBackupData(tag_info.uuid, data);
result = VerifyDeviceResult(device, result);
}
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 0fa29d398..198d0f2b9 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -302,7 +302,7 @@ Result NfcInterface::TranslateResultToServiceError(Result result) const {
return TranslateResultToNfp(result);
}
default:
- if (result != ResultUnknown216) {
+ if (result != ResultBackupPathAlreadyExist) {
return result;
}
return ResultUnknown74;
@@ -343,6 +343,9 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
if (result == ResultApplicationAreaIsNotInitialized) {
return NFP::ResultApplicationAreaIsNotInitialized;
}
+ if (result == ResultCorruptedDataWithBackup) {
+ return NFP::ResultCorruptedDataWithBackup;
+ }
if (result == ResultCorruptedData) {
return NFP::ResultCorruptedData;
}
@@ -355,6 +358,9 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
if (result == ResultNotAnAmiibo) {
return NFP::ResultNotAnAmiibo;
}
+ if (result == ResultUnableToAccessBackupFile) {
+ return NFP::ResultUnableToAccessBackupFile;
+ }
LOG_WARNING(Service_NFC, "Result conversion not handled");
return result;
}
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
index 917d79ef8..59a808740 100644
--- a/src/core/hle/service/nfc/nfc_result.h
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -9,20 +9,22 @@ namespace Service::NFC {
constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
-constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
+constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFC, 68);
constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
-constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
+constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88);
constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
-constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
-constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
-constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
-constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
-constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
-constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
-constexpr Result ResultUnknown216(ErrorModule::NFC, 216);
+constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113);
+constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120);
+constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128);
+constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
+constexpr Result ResultCorruptedData(ErrorModule::NFC, 144);
+constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152);
+constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168);
+constexpr Result ResultNotAnAmiibo(ErrorModule::NFC, 178);
+constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216);
} // namespace Service::NFC
diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp
index 21d159154..34ef9d82d 100644
--- a/src/core/hle/service/nfp/nfp_interface.cpp
+++ b/src/core/hle/service/nfp/nfp_interface.cpp
@@ -126,7 +126,7 @@ void Interface::Flush(HLERequestContext& ctx) {
void Interface::Restore(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
- LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
auto result = GetManager()->Restore(device_handle);
result = TranslateResultToServiceError(result);
@@ -394,7 +394,7 @@ void Interface::BreakTag(HLERequestContext& ctx) {
void Interface::ReadBackupData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
- LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
std::vector<u8> backup_data{};
auto result = GetManager()->ReadBackupData(device_handle, backup_data);
@@ -412,7 +412,7 @@ void Interface::WriteBackupData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto backup_data_buffer{ctx.ReadBuffer()};
- LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
auto result = GetManager()->WriteBackupData(device_handle, backup_data_buffer);
result = TranslateResultToServiceError(result);
diff --git a/src/core/hle/service/nfp/nfp_result.h b/src/core/hle/service/nfp/nfp_result.h
index 4c126cd81..618533843 100644
--- a/src/core/hle/service/nfp/nfp_result.h
+++ b/src/core/hle/service/nfp/nfp_result.h
@@ -17,9 +17,11 @@ constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
+constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFP, 136);
constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
+constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFP, 200);
} // namespace Service::NFP
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 0c7aee1b8..dc45169ad 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -69,7 +69,7 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
void nvhost_nvdec::OnOpen(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
- system.AudioCore().SetNVDECActive(true);
+ system.SetNVDECActive(true);
}
void nvhost_nvdec::OnClose(DeviceFD fd) {
@@ -79,7 +79,7 @@ void nvhost_nvdec::OnClose(DeviceFD fd) {
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
- system.AudioCore().SetNVDECActive(false);
+ system.SetNVDECActive(false);
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 4988e6e17..da2d5890f 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -324,6 +324,10 @@ s64 Nvnflinger::GetNextTicks() const {
speed_scale = 0.01f;
}
}
+ if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
+ // Run at intended presentation rate during video playback.
+ speed_scale = 1.f;
+ }
// As an extension, treat nonpositive swap interval as framerate multiplier.
const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 73d04d7ee..7be6cf5f3 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -33,7 +33,8 @@ static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect s
struct NroHeader {
INSERT_PADDING_BYTES(0x4);
u32_le module_header_offset;
- INSERT_PADDING_BYTES(0x8);
+ u32 magic_ext1;
+ u32 magic_ext2;
u32_le magic;
INSERT_PADDING_BYTES(0x4);
u32_le file_size;
@@ -124,6 +125,16 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
return FileType::Error;
}
+bool AppLoader_NRO::IsHomebrew() {
+ // Read NSO header
+ NroHeader nro_header{};
+ if (sizeof(NroHeader) != file->ReadObject(&nro_header)) {
+ return false;
+ }
+ return nro_header.magic_ext1 == Common::MakeMagic('H', 'O', 'M', 'E') &&
+ nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
+}
+
static constexpr u32 PageAlignSize(u32 size) {
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
}
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index ccb77b581..8de6eebc6 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -38,6 +38,8 @@ public:
*/
static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
+ bool IsHomebrew();
+
FileType GetFileType() const override {
return IdentifyType(file);
}