diff options
| author | 2015-05-10 18:35:37 -0500 | |
|---|---|---|
| committer | 2015-05-10 18:35:37 -0500 | |
| commit | 000876858d52d7e4fa8e21bc4407d43d548eff30 (patch) | |
| tree | f0af4cde78349cfe4ea7875b24d37cf85eb3eb03 /src | |
| parent | Merge pull request #726 from bunnei/gpu-improvements (diff) | |
| download | yuzu-000876858d52d7e4fa8e21bc4407d43d548eff30.tar.gz yuzu-000876858d52d7e4fa8e21bc4407d43d548eff30.tar.xz yuzu-000876858d52d7e4fa8e21bc4407d43d548eff30.zip | |
Core/Memory: Give every emulated thread it's own TLS area.
The TLS area for thread T with id Ti is located at TLS_AREA_VADDR + (Ti - 1) * 0x200.
This allows some games like Mario Kart 7 to continue further.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/arm/arm_interface.h | 3 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom.cpp | 5 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom.h | 2 | ||||
| -rw-r--r-- | src/core/core.cpp | 4 | ||||
| -rw-r--r-- | src/core/core.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/session.h | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 6 |
8 files changed, 31 insertions, 11 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 85ed2c698..976c339e8 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -99,8 +99,9 @@ public: | |||
| 99 | * @param stack_top Pointer to the top of the stack | 99 | * @param stack_top Pointer to the top of the stack |
| 100 | * @param entry_point Entry point for execution | 100 | * @param entry_point Entry point for execution |
| 101 | * @param arg User argument for thread | 101 | * @param arg User argument for thread |
| 102 | * @param tls_address Address of the Thread Local Storage for the thread | ||
| 102 | */ | 103 | */ |
| 103 | virtual void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) = 0; | 104 | virtual void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg, u32 tls_address) = 0; |
| 104 | 105 | ||
| 105 | /** | 106 | /** |
| 106 | * Saves the current CPU context | 107 | * Saves the current CPU context |
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 0072ae533..1de1d2612 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp | |||
| @@ -90,13 +90,14 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) { | |||
| 90 | AddTicks(ticks_executed); | 90 | AddTicks(ticks_executed); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { | 93 | void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg, u32 tls_address) { |
| 94 | memset(&context, 0, sizeof(Core::ThreadContext)); | 94 | memset(&context, 0, sizeof(Core::ThreadContext)); |
| 95 | 95 | ||
| 96 | context.cpu_registers[0] = arg; | 96 | context.cpu_registers[0] = arg; |
| 97 | context.pc = entry_point; | 97 | context.pc = entry_point; |
| 98 | context.sp = stack_top; | 98 | context.sp = stack_top; |
| 99 | context.cpsr = 0x1F; // Usermode | 99 | context.cpsr = 0x1F; // Usermode |
| 100 | context.tls = tls_address; | ||
| 100 | } | 101 | } |
| 101 | 102 | ||
| 102 | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | 103 | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { |
| @@ -123,6 +124,8 @@ void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { | |||
| 123 | 124 | ||
| 124 | state->VFP[1] = ctx.fpscr; | 125 | state->VFP[1] = ctx.fpscr; |
| 125 | state->VFP[2] = ctx.fpexc; | 126 | state->VFP[2] = ctx.fpexc; |
| 127 | |||
| 128 | SetCP15Register(CP15_THREAD_URO, ctx.tls); | ||
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | void ARM_DynCom::PrepareReschedule() { | 131 | void ARM_DynCom::PrepareReschedule() { |
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 2488c879c..b3fd708f1 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h | |||
| @@ -27,7 +27,7 @@ public: | |||
| 27 | 27 | ||
| 28 | void AddTicks(u64 ticks) override; | 28 | void AddTicks(u64 ticks) override; |
| 29 | 29 | ||
| 30 | void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) override; | 30 | void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg, u32 tls_address) override; |
| 31 | void SaveContext(Core::ThreadContext& ctx) override; | 31 | void SaveContext(Core::ThreadContext& ctx) override; |
| 32 | void LoadContext(const Core::ThreadContext& ctx) override; | 32 | void LoadContext(const Core::ThreadContext& ctx) override; |
| 33 | 33 | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index bb2ed7a92..b5c258230 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -61,10 +61,6 @@ int Init() { | |||
| 61 | g_sys_core = new ARM_DynCom(USER32MODE); | 61 | g_sys_core = new ARM_DynCom(USER32MODE); |
| 62 | g_app_core = new ARM_DynCom(USER32MODE); | 62 | g_app_core = new ARM_DynCom(USER32MODE); |
| 63 | 63 | ||
| 64 | // TODO: Whenever TLS is implemented, this should contain | ||
| 65 | // the address of the 0x200-byte TLS | ||
| 66 | g_app_core->SetCP15Register(CP15_THREAD_URO, Memory::TLS_AREA_VADDR); | ||
| 67 | |||
| 68 | LOG_DEBUG(Core, "Initialized OK"); | 64 | LOG_DEBUG(Core, "Initialized OK"); |
| 69 | return 0; | 65 | return 0; |
| 70 | } | 66 | } |
diff --git a/src/core/core.h b/src/core/core.h index 278f0f1cc..215b5a49f 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -21,6 +21,8 @@ struct ThreadContext { | |||
| 21 | u32 fpu_registers[32]; | 21 | u32 fpu_registers[32]; |
| 22 | u32 fpscr; | 22 | u32 fpscr; |
| 23 | u32 fpexc; | 23 | u32 fpexc; |
| 24 | |||
| 25 | u32 tls; | ||
| 24 | }; | 26 | }; |
| 25 | 27 | ||
| 26 | extern ARM_Interface* g_app_core; ///< ARM11 application core | 28 | extern ARM_Interface* g_app_core; ///< ARM11 application core |
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 0fd18148a..8c3886ffd 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/thread.h" | ||
| 8 | #include "core/mem_map.h" | 9 | #include "core/mem_map.h" |
| 9 | 10 | ||
| 10 | namespace Kernel { | 11 | namespace Kernel { |
| @@ -12,12 +13,15 @@ namespace Kernel { | |||
| 12 | static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header | 13 | static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header |
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| 15 | * Returns a pointer to the command buffer in kernel memory | 16 | * Returns a pointer to the command buffer in the current thread's TLS |
| 17 | * TODO(Subv): This is not entirely correct, the command buffer should be copied from | ||
| 18 | * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to | ||
| 19 | * the service handler process' memory. | ||
| 16 | * @param offset Optional offset into command buffer | 20 | * @param offset Optional offset into command buffer |
| 17 | * @return Pointer to command buffer | 21 | * @return Pointer to command buffer |
| 18 | */ | 22 | */ |
| 19 | inline static u32* GetCommandBuffer(const int offset=0) { | 23 | inline static u32* GetCommandBuffer(const int offset = 0) { |
| 20 | return (u32*)Memory::GetPointer(Memory::TLS_AREA_VADDR + kCommandHeaderOffset + offset); | 24 | return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset); |
| 21 | } | 25 | } |
| 22 | 26 | ||
| 23 | /** | 27 | /** |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0a3fd7cb1..61199c12a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -402,9 +402,13 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 402 | thread->name = std::move(name); | 402 | thread->name = std::move(name); |
| 403 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); | 403 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); |
| 404 | 404 | ||
| 405 | VAddr tls_address = Memory::TLS_AREA_VADDR + (thread->thread_id - 1) * 0x200; | ||
| 406 | |||
| 407 | ASSERT_MSG(tls_address < Memory::TLS_AREA_VADDR_END, "Too many threads"); | ||
| 408 | |||
| 405 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used | 409 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used |
| 406 | // to initialize the context | 410 | // to initialize the context |
| 407 | Core::g_app_core->ResetContext(thread->context, stack_top, entry_point, arg); | 411 | Core::g_app_core->ResetContext(thread->context, stack_top, entry_point, arg, tls_address); |
| 408 | 412 | ||
| 409 | ready_queue.push_back(thread->current_priority, thread.get()); | 413 | ready_queue.push_back(thread->current_priority, thread.get()); |
| 410 | thread->status = THREADSTATUS_READY; | 414 | thread->status = THREADSTATUS_READY; |
| @@ -495,6 +499,10 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { | |||
| 495 | context.cpu_registers[1] = output; | 499 | context.cpu_registers[1] = output; |
| 496 | } | 500 | } |
| 497 | 501 | ||
| 502 | VAddr Thread::GetTLSAddress() const { | ||
| 503 | return context.tls; | ||
| 504 | } | ||
| 505 | |||
| 498 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 506 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 499 | 507 | ||
| 500 | void ThreadingInit() { | 508 | void ThreadingInit() { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9958b16e6..17bb69f45 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -135,6 +135,12 @@ public: | |||
| 135 | */ | 135 | */ |
| 136 | void Stop(); | 136 | void Stop(); |
| 137 | 137 | ||
| 138 | /* | ||
| 139 | * Returns the Thread Local Storage address of the current thread | ||
| 140 | * @returns VAddr of the thread's TLS | ||
| 141 | */ | ||
| 142 | VAddr GetTLSAddress() const; | ||
| 143 | |||
| 138 | Core::ThreadContext context; | 144 | Core::ThreadContext context; |
| 139 | 145 | ||
| 140 | u32 thread_id; | 146 | u32 thread_id; |