diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index f59795901..8d65dc84d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -49,6 +49,8 @@ public:
 
     ThreadContext context;
 
+    u32 thread_id;
+
     u32 status;
     u32 entry_point;
     u32 stack_top;
@@ -76,6 +78,9 @@ static Common::ThreadQueueList<Handle> thread_ready_queue;
 static Handle current_thread_handle;
 static Thread* current_thread;
 
+static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
+static u32 next_thread_id; ///< The next available thread id
+
 /// Gets the current thread
 inline Thread* GetCurrentThread() {
     return current_thread;
@@ -325,6 +330,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
     thread_queue.push_back(handle);
     thread_ready_queue.prepare(priority);
 
+    thread->thread_id = next_thread_id++;
     thread->status = THREADSTATUS_DORMANT;
     thread->entry_point = entry_point;
     thread->stack_top = stack_top;
@@ -465,9 +471,21 @@ void Reschedule() {
     }
 }
 
+ResultCode GetThreadId(u32* thread_id, Handle handle) {
+    Thread* thread = g_object_pool.Get<Thread>(handle);
+    if (thread == nullptr)
+        return ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS, 
+                          ErrorSummary::WrongArgument, ErrorLevel::Permanent);
+
+    *thread_id = thread->thread_id;
+
+    return RESULT_SUCCESS;
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
 void ThreadingInit() {
+    next_thread_id = INITIAL_THREAD_ID;
 }
 
 void ThreadingShutdown() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index ce63a70d3..53a19d779 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -58,6 +58,14 @@ void Reschedule();
 /// Stops the current thread
 ResultCode StopThread(Handle thread, const char* reason);
 
+/**
+ * Retrieves the ID of the specified thread handle
+ * @param thread_id Will contain the output thread id
+ * @param handle Handle to the thread we want
+ * @return Whether the function was successful or not
+ */
+ResultCode GetThreadId(u32* thread_id, Handle handle);
+
 /// Resumes a thread from waiting by marking it as "ready"
 void ResumeThreadFromWait(Handle handle);
 
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 43a3cbe03..a5805ed05 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -281,10 +281,11 @@ static Result ReleaseMutex(Handle handle) {
     return res.raw;
 }
 
-/// Get current thread ID
-static Result GetThreadId(u32* thread_id, Handle thread) {
-    ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread);
-    return 0;
+/// Get the ID for the specified thread.
+static Result GetThreadId(u32* thread_id, Handle handle) {
+    DEBUG_LOG(SVC, "called thread=0x%08X", handle);
+    ResultCode result = Kernel::GetThreadId(thread_id, handle);
+    return result.raw;
 }
 
 /// Query memory