Browse Source
Merge pull request #751 from Subv/tpidr_el0
CPU: Save and restore the TPIDR_EL0 system register on every context switch
pull/15/merge
bunnei
8 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with
39 additions and
0 deletions
-
src/core/arm/arm_interface.h
-
src/core/arm/dynarmic/arm_dynarmic.cpp
-
src/core/arm/dynarmic/arm_dynarmic.h
-
src/core/arm/unicorn/arm_unicorn.cpp
-
src/core/arm/unicorn/arm_unicorn.h
-
src/core/hle/kernel/scheduler.cpp
-
src/core/hle/kernel/thread.cpp
-
src/core/hle/kernel/thread.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 |
|
|
|
|
|
|
|
@ -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(); |
|
|
|
|
|
|
|
@ -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; |
|
|
|
|
|
|
|
@ -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)); |
|
|
|
|
|
|
|
@ -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; |
|
|
|
|
|
|
|
@ -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; |
|
|
|
|
|
|
|
@ -312,6 +312,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; |
|
|
|
|
|
|
|
@ -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 |
|
|
|
|
|
|
|
|