From 7d5c3b00a8237d9bfccad7b88224372e15ba0fb6 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Tue, 12 Dec 2017 19:08:53 +0000
Subject: [PATCH 1/2] dynarmic: Update to d1d4705

---
 externals/dynarmic                     | 2 +-
 src/core/arm/dynarmic/arm_dynarmic.cpp | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/externals/dynarmic b/externals/dynarmic
index 4110494ac..d1d470536 160000
--- a/externals/dynarmic
+++ b/externals/dynarmic
@@ -1 +1 @@
-Subproject commit 4110494ac4edc83f74c65834ab3ba6ddd166f42e
+Subproject commit d1d4705364031512cb89333aebc00b8d75a2f732
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 1890e7c5f..2f42c915a 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -30,7 +30,7 @@ static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) {
     state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC);
 
     jit->Regs() = state->Reg;
-    jit->Cpsr() = state->Cpsr;
+    jit->SetCpsr(state->Cpsr);
     jit->ExtRegs() = state->ExtReg;
     jit->SetFpscr(state->VFP[VFP_FPSCR]);
 }
@@ -137,7 +137,7 @@ u32 ARM_Dynarmic::GetCPSR() const {
 }
 
 void ARM_Dynarmic::SetCPSR(u32 cpsr) {
-    jit->Cpsr() = cpsr;
+    jit->SetCpsr(cpsr);
 }
 
 u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) {
@@ -168,7 +168,7 @@ void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
     jit->Regs()[13] = ctx.sp;
     jit->Regs()[14] = ctx.lr;
     jit->Regs()[15] = ctx.pc;
-    jit->Cpsr() = ctx.cpsr;
+    jit->SetCpsr(ctx.cpsr);
 
     jit->SetFpscr(ctx.fpscr);
     interpreter_state->VFP[VFP_FPEXC] = ctx.fpexc;

From fb2d34997e13327ad68b2aa7aa8dd64c20397bb1 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Tue, 12 Dec 2017 19:12:03 +0000
Subject: [PATCH 2/2] core/arm: Backend-specific context implementations

---
 src/citra_qt/debugger/wait_tree.cpp    |  4 +-
 src/core/arm/arm_interface.h           | 56 ++++++++++++---
 src/core/arm/dynarmic/arm_dynarmic.cpp | 88 +++++++++++++++++------
 src/core/arm/dynarmic/arm_dynarmic.h   |  5 +-
 src/core/arm/dyncom/arm_dyncom.cpp     | 96 ++++++++++++++++++++------
 src/core/arm/dyncom/arm_dyncom.h       |  5 +-
 src/core/hle/kernel/svc.cpp            |  4 +-
 src/core/hle/kernel/thread.cpp         | 25 ++++---
 src/core/hle/kernel/thread.h           |  2 +-
 9 files changed, 212 insertions(+), 73 deletions(-)

diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index af0dfeca1..52493c58f 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -172,8 +172,8 @@ QString WaitTreeThread::GetText() const {
         break;
     }
     QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
-                          .arg(thread.context.pc, 8, 16, QLatin1Char('0'))
-                          .arg(thread.context.lr, 8, 16, QLatin1Char('0'));
+                          .arg(thread.context->GetProgramCounter(), 8, 16, QLatin1Char('0'))
+                          .arg(thread.context->GetLinkRegister(), 8, 16, QLatin1Char('0'));
     return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") ";
 }
 
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index e43ac5429..8ac2c043d 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <cstddef>
+#include <memory>
 #include "common/common_types.h"
 #include "core/arm/skyeye_common/arm_regformat.h"
 #include "core/arm/skyeye_common/vfp/asm_vfp.h"
@@ -14,15 +15,42 @@ class ARM_Interface : NonCopyable {
 public:
     virtual ~ARM_Interface() {}
 
-    struct ThreadContext {
-        u32 cpu_registers[13];
-        u32 sp;
-        u32 lr;
-        u32 pc;
-        u32 cpsr;
-        u32 fpu_registers[64];
-        u32 fpscr;
-        u32 fpexc;
+    class ThreadContext {
+    public:
+        virtual ~ThreadContext() = default;
+
+        virtual void Reset() = 0;
+        virtual u32 GetCpuRegister(size_t index) const = 0;
+        virtual void SetCpuRegister(size_t index, u32 value) = 0;
+        virtual u32 GetCpsr() const = 0;
+        virtual void SetCpsr(u32 value) = 0;
+        virtual u32 GetFpuRegister(size_t index) const = 0;
+        virtual void SetFpuRegister(size_t index, u32 value) = 0;
+        virtual u32 GetFpscr() const = 0;
+        virtual void SetFpscr(u32 value) = 0;
+        virtual u32 GetFpexc() const = 0;
+        virtual void SetFpexc(u32 value) = 0;
+
+        u32 GetStackPointer() const {
+            return GetCpuRegister(13);
+        }
+        void SetStackPointer(u32 value) {
+            return SetCpuRegister(13, value);
+        }
+
+        u32 GetLinkRegister() const {
+            return GetCpuRegister(14);
+        }
+        void SetLinkRegister(u32 value) {
+            return SetCpuRegister(14, value);
+        }
+
+        u32 GetProgramCounter() const {
+            return GetCpuRegister(15);
+        }
+        void SetProgramCounter(u32 value) {
+            return SetCpuRegister(15, value);
+        }
     };
 
     /// Runs the CPU until an event happens
@@ -124,17 +152,23 @@ public:
      */
     virtual void SetCP15Register(CP15Register reg, u32 value) = 0;
 
+    /**
+     * Creates a CPU context
+     * @note The created context may only be used with this instance.
+     */
+    virtual std::unique_ptr<ThreadContext> NewContext() const = 0;
+
     /**
      * Saves the current CPU context
      * @param ctx Thread context to save
      */
-    virtual void SaveContext(ThreadContext& ctx) = 0;
+    virtual void SaveContext(const std::unique_ptr<ThreadContext>& ctx) = 0;
 
     /**
      * Loads a CPU context
      * @param ctx Thread context to load
      */
-    virtual void LoadContext(const ThreadContext& ctx) = 0;
+    virtual void LoadContext(const std::unique_ptr<ThreadContext>& ctx) = 0;
 
     /// Prepare core for thread reschedule (if needed to correctly handle state)
     virtual void PrepareReschedule() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 2f42c915a..ce41bef52 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
+#include <dynarmic/context.h>
 #include <dynarmic/dynarmic.h>
 #include "common/assert.h"
 #include "common/microprofile.h"
@@ -14,6 +15,59 @@
 #include "core/hle/kernel/svc.h"
 #include "core/memory.h"
 
+class DynarmicThreadContext final : public ARM_Interface::ThreadContext {
+public:
+    DynarmicThreadContext() {
+        Reset();
+    }
+    ~DynarmicThreadContext() override = default;
+
+    void Reset() override {
+        ctx.Regs() = {};
+        ctx.SetCpsr(0);
+        ctx.ExtRegs() = {};
+        ctx.SetFpscr(0);
+        fpexc = 0;
+    }
+
+    u32 GetCpuRegister(size_t index) const override {
+        return ctx.Regs()[index];
+    }
+    void SetCpuRegister(size_t index, u32 value) override {
+        ctx.Regs()[index] = value;
+    }
+    u32 GetCpsr() const override {
+        return ctx.Cpsr();
+    }
+    void SetCpsr(u32 value) override {
+        ctx.SetCpsr(value);
+    }
+    u32 GetFpuRegister(size_t index) const override {
+        return ctx.ExtRegs()[index];
+    }
+    void SetFpuRegister(size_t index, u32 value) override {
+        ctx.ExtRegs()[index] = value;
+    }
+    u32 GetFpscr() const override {
+        return ctx.Fpscr();
+    }
+    void SetFpscr(u32 value) override {
+        ctx.SetFpscr(value);
+    }
+    u32 GetFpexc() const override {
+        return fpexc;
+    }
+    void SetFpexc(u32 value) override {
+        fpexc = value;
+    }
+
+private:
+    friend class ARM_Dynarmic;
+
+    Dynarmic::Context ctx;
+    u32 fpexc;
+};
+
 static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) {
     ARMul_State* state = static_cast<ARMul_State*>(user_arg);
 
@@ -148,30 +202,24 @@ void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) {
     interpreter_state->CP15[reg] = value;
 }
 
-void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
-    memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers));
-    memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers));
-
-    ctx.sp = jit->Regs()[13];
-    ctx.lr = jit->Regs()[14];
-    ctx.pc = jit->Regs()[15];
-    ctx.cpsr = jit->Cpsr();
-
-    ctx.fpscr = jit->Fpscr();
-    ctx.fpexc = interpreter_state->VFP[VFP_FPEXC];
+std::unique_ptr<ARM_Interface::ThreadContext> ARM_Dynarmic::NewContext() const {
+    return std::make_unique<DynarmicThreadContext>();
 }
 
-void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
-    memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
-    memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
+void ARM_Dynarmic::SaveContext(const std::unique_ptr<ThreadContext>& arg) {
+    DynarmicThreadContext* ctx = dynamic_cast<DynarmicThreadContext*>(arg.get());
+    ASSERT(ctx);
 
-    jit->Regs()[13] = ctx.sp;
-    jit->Regs()[14] = ctx.lr;
-    jit->Regs()[15] = ctx.pc;
-    jit->SetCpsr(ctx.cpsr);
+    jit->SaveContext(ctx->ctx);
+    ctx->fpexc = interpreter_state->VFP[VFP_FPEXC];
+}
 
-    jit->SetFpscr(ctx.fpscr);
-    interpreter_state->VFP[VFP_FPEXC] = ctx.fpexc;
+void ARM_Dynarmic::LoadContext(const std::unique_ptr<ThreadContext>& arg) {
+    const DynarmicThreadContext* ctx = dynamic_cast<DynarmicThreadContext*>(arg.get());
+    ASSERT(ctx);
+
+    jit->LoadContext(ctx->ctx);
+    interpreter_state->VFP[VFP_FPEXC] = ctx->fpexc;
 }
 
 void ARM_Dynarmic::PrepareReschedule() {
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 011ffc54a..fa3023cb9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -35,8 +35,9 @@ public:
     u32 GetCP15Register(CP15Register reg) override;
     void SetCP15Register(CP15Register reg, u32 value) override;
 
-    void SaveContext(ThreadContext& ctx) override;
-    void LoadContext(const ThreadContext& ctx) override;
+    std::unique_ptr<ThreadContext> NewContext() const override;
+    void SaveContext(const std::unique_ptr<ThreadContext>& arg) override;
+    void LoadContext(const std::unique_ptr<ThreadContext>& arg) override;
 
     void PrepareReschedule() override;
 
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 976a438ef..4643a20a7 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -12,6 +12,62 @@
 #include "core/core.h"
 #include "core/core_timing.h"
 
+class DynComThreadContext final : public ARM_Interface::ThreadContext {
+public:
+    DynComThreadContext() {
+        Reset();
+    }
+    ~DynComThreadContext() override = default;
+
+    void Reset() override {
+        cpu_registers = {};
+        cpsr = 0;
+        fpu_registers = {};
+        fpscr = 0;
+        fpexc = 0;
+    }
+
+    u32 GetCpuRegister(size_t index) const override {
+        return cpu_registers[index];
+    }
+    void SetCpuRegister(size_t index, u32 value) override {
+        cpu_registers[index] = value;
+    }
+    u32 GetCpsr() const override {
+        return cpsr;
+    }
+    void SetCpsr(u32 value) override {
+        cpsr = value;
+    }
+    u32 GetFpuRegister(size_t index) const override {
+        return fpu_registers[index];
+    }
+    void SetFpuRegister(size_t index, u32 value) override {
+        fpu_registers[index] = value;
+    }
+    u32 GetFpscr() const override {
+        return fpscr;
+    }
+    void SetFpscr(u32 value) override {
+        fpscr = value;
+    }
+    u32 GetFpexc() const override {
+        return fpexc;
+    }
+    void SetFpexc(u32 value) override {
+        fpexc = value;
+    }
+
+private:
+    friend class ARM_DynCom;
+
+    std::array<u32, 16> cpu_registers;
+    u32 cpsr;
+    std::array<u32, 64> fpu_registers;
+    u32 fpscr;
+    u32 fpexc;
+};
+
 ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
     state = std::make_unique<ARMul_State>(initial_mode);
 }
@@ -93,30 +149,30 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
     CoreTiming::AddTicks(ticks_executed);
 }
 
-void ARM_DynCom::SaveContext(ThreadContext& ctx) {
-    memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers));
-    memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers));
-
-    ctx.sp = state->Reg[13];
-    ctx.lr = state->Reg[14];
-    ctx.pc = state->Reg[15];
-    ctx.cpsr = state->Cpsr;
-
-    ctx.fpscr = state->VFP[VFP_FPSCR];
-    ctx.fpexc = state->VFP[VFP_FPEXC];
+std::unique_ptr<ARM_Interface::ThreadContext> ARM_DynCom::NewContext() const {
+    return std::make_unique<DynComThreadContext>();
 }
 
-void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
-    memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
-    memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
+void ARM_DynCom::SaveContext(const std::unique_ptr<ThreadContext>& arg) {
+    DynComThreadContext* ctx = dynamic_cast<DynComThreadContext*>(arg.get());
+    ASSERT(ctx);
 
-    state->Reg[13] = ctx.sp;
-    state->Reg[14] = ctx.lr;
-    state->Reg[15] = ctx.pc;
-    state->Cpsr = ctx.cpsr;
+    ctx->cpu_registers = state->Reg;
+    ctx->cpsr = state->Cpsr;
+    ctx->fpu_registers = state->ExtReg;
+    ctx->fpscr = state->VFP[VFP_FPSCR];
+    ctx->fpexc = state->VFP[VFP_FPEXC];
+}
 
-    state->VFP[VFP_FPSCR] = ctx.fpscr;
-    state->VFP[VFP_FPEXC] = ctx.fpexc;
+void ARM_DynCom::LoadContext(const std::unique_ptr<ThreadContext>& arg) {
+    DynComThreadContext* ctx = dynamic_cast<DynComThreadContext*>(arg.get());
+    ASSERT(ctx);
+
+    state->Reg = ctx->cpu_registers;
+    state->Cpsr = ctx->cpsr;
+    state->ExtReg = ctx->fpu_registers;
+    state->VFP[VFP_FPSCR] = ctx->fpscr;
+    state->VFP[VFP_FPEXC] = ctx->fpexc;
 }
 
 void ARM_DynCom::PrepareReschedule() {
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index aa7520011..5547e0cc7 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -35,8 +35,9 @@ public:
     u32 GetCP15Register(CP15Register reg) override;
     void SetCP15Register(CP15Register reg, u32 value) override;
 
-    void SaveContext(ThreadContext& ctx) override;
-    void LoadContext(const ThreadContext& ctx) override;
+    std::unique_ptr<ThreadContext> NewContext() const override;
+    void SaveContext(const std::unique_ptr<ThreadContext>& arg) override;
+    void LoadContext(const std::unique_ptr<ThreadContext>& arg) override;
 
     void PrepareReschedule() override;
 
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 06c905284..c529e6115 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -733,8 +733,8 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point
                    Thread::Create(name, entry_point, priority, arg, processor_id, stack_top,
                                   g_current_process));
 
-    thread->context.fpscr =
-        FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000
+    thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
+                              FPSCR_ROUND_TOZERO); // 0x03C00000
 
     CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(thread)));
 
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 92eceb98f..8430f5e0d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -60,7 +60,7 @@ inline static u32 const NewThreadId() {
     return next_thread_id++;
 }
 
-Thread::Thread() {}
+Thread::Thread() : context(Core::CPU().NewContext()) {}
 Thread::~Thread() {}
 
 Thread* GetCurrentThread() {
@@ -309,14 +309,13 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
  * @param entry_point Address of entry point for execution
  * @param arg User argument for thread
  */
-static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_top,
-                               u32 entry_point, u32 arg) {
-    memset(&context, 0, sizeof(ARM_Interface::ThreadContext));
-
-    context.cpu_registers[0] = arg;
-    context.pc = entry_point;
-    context.sp = stack_top;
-    context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode
+static void ResetThreadContext(const std::unique_ptr<ARM_Interface::ThreadContext>& context,
+                               u32 stack_top, u32 entry_point, u32 arg) {
+    context->Reset();
+    context->SetCpuRegister(0, arg);
+    context->SetProgramCounter(entry_point);
+    context->SetStackPointer(stack_top);
+    context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode
 }
 
 ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority,
@@ -453,8 +452,8 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Proce
 
     SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
 
-    thread->context.fpscr =
-        FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
+    thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO |
+                              FPSCR_IXC); // 0x03C00010
 
     // Note: The newly created thread will be run when the scheduler fires.
     return thread;
@@ -480,11 +479,11 @@ void Reschedule() {
 }
 
 void Thread::SetWaitSynchronizationResult(ResultCode result) {
-    context.cpu_registers[0] = result.raw;
+    context->SetCpuRegister(0, result.raw);
 }
 
 void Thread::SetWaitSynchronizationOutput(s32 output) {
-    context.cpu_registers[1] = output;
+    context->SetCpuRegister(1, output);
 }
 
 s32 Thread::GetWaitObjectIndex(WaitObject* object) const {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 05e536086..e80b4cb5e 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -181,7 +181,7 @@ public:
         return status == THREADSTATUS_WAIT_SYNCH_ALL;
     }
 
-    ARM_Interface::ThreadContext context;
+    std::unique_ptr<ARM_Interface::ThreadContext> context;
 
     u32 thread_id;