diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index eb4fef3815..3fa5f51f14 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -22,6 +22,8 @@ set(SRCS core.cpp
hle/config_mem.cpp
hle/coprocessor.cpp
hle/syscall.cpp
+ hle/kernel/kernel.cpp
+ hle/kernel/thread.cpp
hle/service/apt.cpp
hle/service/gsp.cpp
hle/service/hid.cpp
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index b56661e48b..59fc6f4fcf 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -156,6 +156,8 @@
+
+
@@ -198,6 +200,8 @@
+
+
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index 5c947ec23f..ff988c1161 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -28,6 +28,9 @@
{812c5189-ca49-4704-b842-3ffad09092d3}
+
+ {f2b132eb-caff-4b04-aaae-88d24393a711}
+
@@ -114,6 +117,12 @@
hle
+
+ hle\kernel
+
+
+ hle\kernel
+
@@ -223,6 +232,12 @@
hle
+
+ hle\kernel
+
+
+ hle\kernel
+
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
new file mode 100644
index 0000000000..fc494fe30f
--- /dev/null
+++ b/src/core/hle/kernel/kernel.cpp
@@ -0,0 +1,142 @@
+// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#include "common/common.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+
+KernelObjectPool g_kernel_objects;
+
+void __KernelInit() {
+ __KernelThreadingInit();
+}
+
+void __KernelShutdown() {
+ __KernelThreadingShutdown();
+}
+
+KernelObjectPool::KernelObjectPool() {
+ memset(occupied, 0, sizeof(bool) * MAX_COUNT);
+ next_id = INITIAL_NEXT_ID;
+}
+
+UID KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top) {
+ if (range_top > MAX_COUNT) {
+ range_top = MAX_COUNT;
+ }
+ if (next_id >= range_bottom && next_id < range_top) {
+ range_bottom = next_id++;
+ }
+ for (int i = range_bottom; i < range_top; i++) {
+ if (!occupied[i]) {
+ occupied[i] = true;
+ pool[i] = obj;
+ pool[i]->uid = i + HANDLE_OFFSET;
+ return i + HANDLE_OFFSET;
+ }
+ }
+ ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use.");
+ return 0;
+}
+
+bool KernelObjectPool::IsValid(UID handle)
+{
+ int index = handle - HANDLE_OFFSET;
+ if (index < 0)
+ return false;
+ if (index >= MAX_COUNT)
+ return false;
+
+ return occupied[index];
+}
+
+void KernelObjectPool::Clear()
+{
+ for (int i = 0; i < MAX_COUNT; i++)
+ {
+ //brutally clear everything, no validation
+ if (occupied[i])
+ delete pool[i];
+ occupied[i] = false;
+ }
+ memset(pool, 0, sizeof(KernelObject*)*MAX_COUNT);
+ next_id = INITIAL_NEXT_ID;
+}
+
+KernelObject *&KernelObjectPool::operator [](UID handle)
+{
+ _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
+ return pool[handle - HANDLE_OFFSET];
+}
+
+void KernelObjectPool::List() {
+ for (int i = 0; i < MAX_COUNT; i++) {
+ if (occupied[i]) {
+ if (pool[i]) {
+ INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName(),
+ pool[i]->GetName());
+ }
+ }
+ }
+}
+
+int KernelObjectPool::GetCount()
+{
+ int count = 0;
+ for (int i = 0; i < MAX_COUNT; i++)
+ {
+ if (occupied[i])
+ count++;
+ }
+ return count;
+}
+
+KernelObject *KernelObjectPool::CreateByIDType(int type) {
+ // Used for save states. This is ugly, but what other way is there?
+ switch (type) {
+ //case SCE_KERNEL_TMID_Alarm:
+ // return __KernelAlarmObject();
+ //case SCE_KERNEL_TMID_EventFlag:
+ // return __KernelEventFlagObject();
+ //case SCE_KERNEL_TMID_Mbox:
+ // return __KernelMbxObject();
+ //case SCE_KERNEL_TMID_Fpl:
+ // return __KernelMemoryFPLObject();
+ //case SCE_KERNEL_TMID_Vpl:
+ // return __KernelMemoryVPLObject();
+ //case PPSSPP_KERNEL_TMID_PMB:
+ // return __KernelMemoryPMBObject();
+ //case PPSSPP_KERNEL_TMID_Module:
+ // return __KernelModuleObject();
+ //case SCE_KERNEL_TMID_Mpipe:
+ // return __KernelMsgPipeObject();
+ //case SCE_KERNEL_TMID_Mutex:
+ // return __KernelMutexObject();
+ //case SCE_KERNEL_TMID_LwMutex:
+ // return __KernelLwMutexObject();
+ //case SCE_KERNEL_TMID_Semaphore:
+ // return __KernelSemaphoreObject();
+ //case SCE_KERNEL_TMID_Callback:
+ // return __KernelCallbackObject();
+ //case SCE_KERNEL_TMID_Thread:
+ // return __KernelThreadObject();
+ //case SCE_KERNEL_TMID_VTimer:
+ // return __KernelVTimerObject();
+ //case SCE_KERNEL_TMID_Tlspl:
+ // return __KernelTlsplObject();
+ //case PPSSPP_KERNEL_TMID_File:
+ // return __KernelFileNodeObject();
+ //case PPSSPP_KERNEL_TMID_DirList:
+ // return __KernelDirListingObject();
+
+ default:
+ ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
+ return NULL;
+ }
+}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
new file mode 100644
index 0000000000..2381ca7f74
--- /dev/null
+++ b/src/core/hle/kernel/kernel.h
@@ -0,0 +1,121 @@
+// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+typedef u32 UID;
+
+class KernelObjectPool;
+
+class KernelObject {
+ friend class KernelObjectPool;
+ u32 uid;
+public:
+ virtual ~KernelObject() {}
+ UID GetUID() const { return uid; }
+ virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; }
+ virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; }
+ virtual int GetIDType() const = 0;
+ //virtual void GetQuickInfo(char *ptr, int size);
+};
+
+class KernelObjectPool {
+public:
+ KernelObjectPool();
+ ~KernelObjectPool() {}
+
+ // Allocates a UID within the range and inserts the object into the map.
+ UID Create(KernelObject *obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF);
+
+ static KernelObject *CreateByIDType(int type);
+
+ template
+ u32 Destroy(UID handle) {
+ u32 error;
+ if (Get(handle, error)) {
+ occupied[handle - handleOffset] = false;
+ delete pool[handle - handleOffset];
+ }
+ return error;
+ };
+
+ bool IsValid(UID handle);
+
+ template
+ T* Get(UID handle, u32& outError) {
+ if (handle < handleOffset || handle >= handleOffset + maxCount || !occupied[handle - handleOffset]) {
+ // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP
+ if (handle != 0 && (u32)handle != 0x80020001) {
+ WARN_LOG(SCEKERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
+ }
+ outError = T::GetMissingErrorCode();
+ return 0;
+ } else {
+ // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally,
+ // it just acted as a static case and everything worked. This means that we will never
+ // see the Wrong type object error below, but we'll just have to live with that danger.
+ T* t = static_cast(pool[handle - handleOffset]);
+ if (t == 0 || t->GetIDType() != T::GetStaticIDType()) {
+ WARN_LOG(SCEKERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
+ outError = T::GetMissingErrorCode();
+ return 0;
+ }
+ outError = SCE_KERNEL_ERROR_OK;
+ return t;
+ }
+ }
+
+ // ONLY use this when you know the handle is valid.
+ template
+ T *GetFast(UID handle) {
+ const UID realHandle = handle - handleOffset;
+ _dbg_assert_(SCEKERNEL, realHandle >= 0 && realHandle < maxCount && occupied[realHandle]);
+ return static_cast(pool[realHandle]);
+ }
+
+ template
+ void Iterate(bool func(T *, ArgT), ArgT arg) {
+ int type = T::GetStaticIDType();
+ for (int i = 0; i < maxCount; i++)
+ {
+ if (!occupied[i])
+ continue;
+ T *t = static_cast(pool[i]);
+ if (t->GetIDType() == type) {
+ if (!func(t, arg))
+ break;
+ }
+ }
+ }
+
+ bool GetIDType(UID handle, int *type) const {
+ if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) ||
+ !occupied[handle - HANDLE_OFFSET]) {
+ ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
+ return false;
+ }
+ KernelObject *t = pool[handle - HANDLE_OFFSET];
+ *type = t->GetIDType();
+ return true;
+ }
+
+ KernelObject *&operator [](UID handle);
+ void List();
+ void Clear();
+ int GetCount();
+
+private:
+ enum {
+ MAX_COUNT = 0x1000,
+ HANDLE_OFFSET = 0x100,
+ INITIAL_NEXT_ID = 0x10,
+ };
+ KernelObject *pool[MAX_COUNT];
+ bool occupied[MAX_COUNT];
+ int next_id;
+};
+
+extern KernelObjectPool g_kernel_objects;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
new file mode 100644
index 0000000000..0ed35de83f
--- /dev/null
+++ b/src/core/hle/kernel/thread.cpp
@@ -0,0 +1,228 @@
+// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include
+
+#include
+#include
+#include