From d17f148e48afe5c43673da4dbb9ee45c640fa52f Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 2 Jan 2018 12:07:26 -0500 Subject: [PATCH] Services/GSP: Assign a thread id to each connected session when the session is created. Most applications call AcquireRight before calling RegisterInterruptRelayQueue so we can't assign the thread id there. This fixes the bug with LLE applets not launching properly. --- src/core/hle/service/gsp/gsp_gpu.cpp | 26 +++++++++++++++++++++----- src/core/hle/service/gsp/gsp_gpu.h | 7 +++---- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp index 11f9f4ae6..7156f3f5c 100644 --- a/src/core/hle/service/gsp/gsp_gpu.cpp +++ b/src/core/hle/service/gsp/gsp_gpu.cpp @@ -53,6 +53,17 @@ constexpr ResultCode ERR_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorM /// Maximum number of threads that can be registered at the same time in the GSP module. constexpr u32 MaxGSPThreads = 4; +/// Thread ids currently in use by the sessions connected to the GSPGPU service. +static std::array used_thread_ids = {false, false, false, false}; + +static u32 GetUnusedThreadId() { + for (u32 id = 0; id < MaxGSPThreads; ++id) { + if (!used_thread_ids[id]) + return id; + } + ASSERT_MSG(false, "All GSP threads are in use"); +} + /// Gets a pointer to a thread command buffer in GSP shared memory static inline u8* GetCommandBuffer(Kernel::SharedPtr shared_memory, u32 thread_id) { @@ -327,11 +338,7 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { interrupt_event->name = "GSP_GSP_GPU::interrupt_event"; - u32 thread_id = next_thread_id++; - ASSERT_MSG(thread_id < MaxGSPThreads, "GSP thread id overflow"); - SessionData* session_data = GetSessionData(ctx.Session()); - session_data->thread_id = thread_id; session_data->interrupt_event = std::move(interrupt_event); session_data->registered = true; @@ -345,7 +352,7 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } - rb.Push(thread_id); + rb.Push(session_data->thread_id); rb.PushCopyObjects(shared_memory); LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags); @@ -752,5 +759,14 @@ GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) { first_initialization = true; }; + +SessionData::SessionData() { + // Assign a new thread id to this session when it connects. Note: In the real GSP service this + // is done through a real thread (svcCreateThread) but we have to simulate it since our HLE + // services don't have threads. + thread_id = GetUnusedThreadId(); + used_thread_ids[thread_id] = true; +} + } // namespace GSP } // namespace Service diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h index 01bab8652..c057dffc4 100644 --- a/src/core/hle/service/gsp/gsp_gpu.h +++ b/src/core/hle/service/gsp/gsp_gpu.h @@ -180,10 +180,12 @@ struct CommandBuffer { static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size"); struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase { + SessionData(); + /// Event triggered when GSP interrupt has been signalled Kernel::SharedPtr interrupt_event; /// Thread index into interrupt relay queue - u32 thread_id = 0; + u32 thread_id; /// Whether RegisterInterruptRelayQueue was called for this session bool registered = false; }; @@ -363,9 +365,6 @@ private: /// Returns the session data for the specified registered thread id, or nullptr if not found. SessionData* FindRegisteredThreadData(u32 thread_id); - /// Next threadid value to use when RegisterInterruptRelayQueue is called. - u32 next_thread_id = 0; - /// GSP shared memory Kernel::SharedPtr shared_memory;