Browse Source

CPU: Save and restore the TPIDR_EL0 system register on every context switch.

Note that there's currently a dynarmic bug preventing this register from being written.
Subv 8 năm trước cách đây
mục cha
commit
d84eb9dac6

+ 4 - 0
src/core/arm/arm_interface.h

@@ -104,6 +104,10 @@ public:
 
     virtual void SetTlsAddress(VAddr address) = 0;
 
+    virtual u64 GetTPIDR_EL0() const = 0;
+
+    virtual void SetTPIDR_EL0(u64 value) = 0;
+
     /**
      * Saves the current CPU context
      * @param ctx Thread context to save

+ 8 - 0
src/core/arm/dynarmic/arm_dynarmic.cpp

@@ -196,6 +196,14 @@ void ARM_Dynarmic::SetTlsAddress(u64 address) {
     cb->tpidrro_el0 = address;
 }
 
+u64 ARM_Dynarmic::GetTPIDR_EL0() const {
+    return cb->tpidr_el0;
+}
+
+void ARM_Dynarmic::SetTPIDR_EL0(u64 value) {
+    cb->tpidr_el0 = value;
+}
+
 void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
     ctx.cpu_registers = jit->GetRegisters();
     ctx.sp = jit->GetSP();

+ 2 - 0
src/core/arm/dynarmic/arm_dynarmic.h

@@ -34,6 +34,8 @@ public:
     void SetCPSR(u32 cpsr) override;
     VAddr GetTlsAddress() const override;
     void SetTlsAddress(VAddr address) override;
+    void SetTPIDR_EL0(u64 value) override;
+    u64 GetTPIDR_EL0() const override;
 
     void SaveContext(ThreadContext& ctx) override;
     void LoadContext(const ThreadContext& ctx) override;

+ 10 - 0
src/core/arm/unicorn/arm_unicorn.cpp

@@ -169,6 +169,16 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) {
     CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
 }
 
+u64 ARM_Unicorn::GetTPIDR_EL0() const {
+    u64 value{};
+    CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
+    return value;
+}
+
+void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
+    CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
+}
+
 void ARM_Unicorn::Run() {
     if (GDBStub::IsServerEnabled()) {
         ExecuteInstructions(std::max(4000000, 0));

+ 2 - 0
src/core/arm/unicorn/arm_unicorn.h

@@ -28,6 +28,8 @@ public:
     void SetCPSR(u32 cpsr) override;
     VAddr GetTlsAddress() const override;
     void SetTlsAddress(VAddr address) override;
+    void SetTPIDR_EL0(u64 value) override;
+    u64 GetTPIDR_EL0() const override;
     void SaveContext(ThreadContext& ctx) override;
     void LoadContext(const ThreadContext& ctx) override;
     void PrepareReschedule() override;

+ 3 - 0
src/core/hle/kernel/scheduler.cpp

@@ -56,6 +56,8 @@ void Scheduler::SwitchContext(Thread* new_thread) {
     if (previous_thread) {
         previous_thread->last_running_ticks = CoreTiming::GetTicks();
         cpu_core->SaveContext(previous_thread->context);
+        // Save the TPIDR_EL0 system register in case it was modified.
+        previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0();
 
         if (previous_thread->status == THREADSTATUS_RUNNING) {
             // This is only the case when a reschedule is triggered without the current thread
@@ -87,6 +89,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
 
         cpu_core->LoadContext(new_thread->context);
         cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
+        cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
         cpu_core->ClearExclusiveState();
     } else {
         current_thread = nullptr;

+ 1 - 0
src/core/hle/kernel/thread.cpp

@@ -313,6 +313,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
     thread->status = THREADSTATUS_DORMANT;
     thread->entry_point = entry_point;
     thread->stack_top = stack_top;
+    thread->tpidr_el0 = 0;
     thread->nominal_priority = thread->current_priority = priority;
     thread->last_running_ticks = CoreTiming::GetTicks();
     thread->processor_id = processor_id;

+ 9 - 0
src/core/hle/kernel/thread.h

@@ -182,6 +182,14 @@ public:
         return tls_address;
     }
 
+    /*
+     * Returns the value of the TPIDR_EL0 Read/Write system register for this thread.
+     * @returns The value of the TPIDR_EL0 register.
+     */
+    u64 GetTPIDR_EL0() const {
+        return tpidr_el0;
+    }
+
     /*
      * Returns the address of the current thread's command buffer, located in the TLS.
      * @returns VAddr of the thread's command buffer.
@@ -213,6 +221,7 @@ public:
     s32 processor_id;
 
     VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
+    u64 tpidr_el0;     ///< TPIDR_EL0 read/write system register.
 
     SharedPtr<Process> owner_process; ///< Process that owns this thread