diff options
| author | 2014-05-09 22:11:18 -0400 | |
|---|---|---|
| committer | 2014-05-09 22:11:18 -0400 | |
| commit | 6b264518a50ce21cb1be55ff3eac4e1c85582cfe (patch) | |
| tree | 036ae3be74768165fbb4ee24db4cdba4ffadec2e /src | |
| parent | added kernel logger to common (diff) | |
| download | yuzu-6b264518a50ce21cb1be55ff3eac4e1c85582cfe.tar.gz yuzu-6b264518a50ce21cb1be55ff3eac4e1c85582cfe.tar.xz yuzu-6b264518a50ce21cb1be55ff3eac4e1c85582cfe.zip | |
added initial kernel/thread modules
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/core.vcxproj | 4 | ||||
| -rw-r--r-- | src/core/core.vcxproj.filters | 15 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 142 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 121 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 228 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 36 |
7 files changed, 548 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eb4fef381..3fa5f51f1 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -22,6 +22,8 @@ set(SRCS core.cpp | |||
| 22 | hle/config_mem.cpp | 22 | hle/config_mem.cpp |
| 23 | hle/coprocessor.cpp | 23 | hle/coprocessor.cpp |
| 24 | hle/syscall.cpp | 24 | hle/syscall.cpp |
| 25 | hle/kernel/kernel.cpp | ||
| 26 | hle/kernel/thread.cpp | ||
| 25 | hle/service/apt.cpp | 27 | hle/service/apt.cpp |
| 26 | hle/service/gsp.cpp | 28 | hle/service/gsp.cpp |
| 27 | hle/service/hid.cpp | 29 | hle/service/hid.cpp |
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index b56661e48..59fc6f4fc 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj | |||
| @@ -156,6 +156,8 @@ | |||
| 156 | <ClCompile Include="hle\config_mem.cpp" /> | 156 | <ClCompile Include="hle\config_mem.cpp" /> |
| 157 | <ClCompile Include="hle\coprocessor.cpp" /> | 157 | <ClCompile Include="hle\coprocessor.cpp" /> |
| 158 | <ClCompile Include="hle\hle.cpp" /> | 158 | <ClCompile Include="hle\hle.cpp" /> |
| 159 | <ClCompile Include="hle\kernel\kernel.cpp" /> | ||
| 160 | <ClCompile Include="hle\kernel\thread.cpp" /> | ||
| 159 | <ClCompile Include="hle\service\apt.cpp" /> | 161 | <ClCompile Include="hle\service\apt.cpp" /> |
| 160 | <ClCompile Include="hle\service\gsp.cpp" /> | 162 | <ClCompile Include="hle\service\gsp.cpp" /> |
| 161 | <ClCompile Include="hle\service\hid.cpp" /> | 163 | <ClCompile Include="hle\service\hid.cpp" /> |
| @@ -198,6 +200,8 @@ | |||
| 198 | <ClInclude Include="hle\coprocessor.h" /> | 200 | <ClInclude Include="hle\coprocessor.h" /> |
| 199 | <ClInclude Include="hle\function_wrappers.h" /> | 201 | <ClInclude Include="hle\function_wrappers.h" /> |
| 200 | <ClInclude Include="hle\hle.h" /> | 202 | <ClInclude Include="hle\hle.h" /> |
| 203 | <ClInclude Include="hle\kernel\kernel.h" /> | ||
| 204 | <ClInclude Include="hle\kernel\thread.h" /> | ||
| 201 | <ClInclude Include="hle\service\apt.h" /> | 205 | <ClInclude Include="hle\service\apt.h" /> |
| 202 | <ClInclude Include="hle\service\gsp.h" /> | 206 | <ClInclude Include="hle\service\gsp.h" /> |
| 203 | <ClInclude Include="hle\service\hid.h" /> | 207 | <ClInclude Include="hle\service\hid.h" /> |
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 5c947ec23..ff988c116 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters | |||
| @@ -28,6 +28,9 @@ | |||
| 28 | <Filter Include="hle\service"> | 28 | <Filter Include="hle\service"> |
| 29 | <UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier> | 29 | <UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier> |
| 30 | </Filter> | 30 | </Filter> |
| 31 | <Filter Include="hle\kernel"> | ||
| 32 | <UniqueIdentifier>{f2b132eb-caff-4b04-aaae-88d24393a711}</UniqueIdentifier> | ||
| 33 | </Filter> | ||
| 31 | </ItemGroup> | 34 | </ItemGroup> |
| 32 | <ItemGroup> | 35 | <ItemGroup> |
| 33 | <ClCompile Include="arm\disassembler\arm_disasm.cpp"> | 36 | <ClCompile Include="arm\disassembler\arm_disasm.cpp"> |
| @@ -114,6 +117,12 @@ | |||
| 114 | <ClCompile Include="hle\config_mem.cpp"> | 117 | <ClCompile Include="hle\config_mem.cpp"> |
| 115 | <Filter>hle</Filter> | 118 | <Filter>hle</Filter> |
| 116 | </ClCompile> | 119 | </ClCompile> |
| 120 | <ClCompile Include="hle\kernel\thread.cpp"> | ||
| 121 | <Filter>hle\kernel</Filter> | ||
| 122 | </ClCompile> | ||
| 123 | <ClCompile Include="hle\kernel\kernel.cpp"> | ||
| 124 | <Filter>hle\kernel</Filter> | ||
| 125 | </ClCompile> | ||
| 117 | </ItemGroup> | 126 | </ItemGroup> |
| 118 | <ItemGroup> | 127 | <ItemGroup> |
| 119 | <ClInclude Include="arm\disassembler\arm_disasm.h"> | 128 | <ClInclude Include="arm\disassembler\arm_disasm.h"> |
| @@ -223,6 +232,12 @@ | |||
| 223 | <ClInclude Include="hle\config_mem.h"> | 232 | <ClInclude Include="hle\config_mem.h"> |
| 224 | <Filter>hle</Filter> | 233 | <Filter>hle</Filter> |
| 225 | </ClInclude> | 234 | </ClInclude> |
| 235 | <ClInclude Include="hle\kernel\thread.h"> | ||
| 236 | <Filter>hle\kernel</Filter> | ||
| 237 | </ClInclude> | ||
| 238 | <ClInclude Include="hle\kernel\kernel.h"> | ||
| 239 | <Filter>hle\kernel</Filter> | ||
| 240 | </ClInclude> | ||
| 226 | </ItemGroup> | 241 | </ItemGroup> |
| 227 | <ItemGroup> | 242 | <ItemGroup> |
| 228 | <Text Include="CMakeLists.txt" /> | 243 | <Text Include="CMakeLists.txt" /> |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp new file mode 100644 index 000000000..fc494fe30 --- /dev/null +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "common/common.h" | ||
| 10 | |||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | |||
| 14 | KernelObjectPool g_kernel_objects; | ||
| 15 | |||
| 16 | void __KernelInit() { | ||
| 17 | __KernelThreadingInit(); | ||
| 18 | } | ||
| 19 | |||
| 20 | void __KernelShutdown() { | ||
| 21 | __KernelThreadingShutdown(); | ||
| 22 | } | ||
| 23 | |||
| 24 | KernelObjectPool::KernelObjectPool() { | ||
| 25 | memset(occupied, 0, sizeof(bool) * MAX_COUNT); | ||
| 26 | next_id = INITIAL_NEXT_ID; | ||
| 27 | } | ||
| 28 | |||
| 29 | UID KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top) { | ||
| 30 | if (range_top > MAX_COUNT) { | ||
| 31 | range_top = MAX_COUNT; | ||
| 32 | } | ||
| 33 | if (next_id >= range_bottom && next_id < range_top) { | ||
| 34 | range_bottom = next_id++; | ||
| 35 | } | ||
| 36 | for (int i = range_bottom; i < range_top; i++) { | ||
| 37 | if (!occupied[i]) { | ||
| 38 | occupied[i] = true; | ||
| 39 | pool[i] = obj; | ||
| 40 | pool[i]->uid = i + HANDLE_OFFSET; | ||
| 41 | return i + HANDLE_OFFSET; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use."); | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | bool KernelObjectPool::IsValid(UID handle) | ||
| 49 | { | ||
| 50 | int index = handle - HANDLE_OFFSET; | ||
| 51 | if (index < 0) | ||
| 52 | return false; | ||
| 53 | if (index >= MAX_COUNT) | ||
| 54 | return false; | ||
| 55 | |||
| 56 | return occupied[index]; | ||
| 57 | } | ||
| 58 | |||
| 59 | void KernelObjectPool::Clear() | ||
| 60 | { | ||
| 61 | for (int i = 0; i < MAX_COUNT; i++) | ||
| 62 | { | ||
| 63 | //brutally clear everything, no validation | ||
| 64 | if (occupied[i]) | ||
| 65 | delete pool[i]; | ||
| 66 | occupied[i] = false; | ||
| 67 | } | ||
| 68 | memset(pool, 0, sizeof(KernelObject*)*MAX_COUNT); | ||
| 69 | next_id = INITIAL_NEXT_ID; | ||
| 70 | } | ||
| 71 | |||
| 72 | KernelObject *&KernelObjectPool::operator [](UID handle) | ||
| 73 | { | ||
| 74 | _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ"); | ||
| 75 | return pool[handle - HANDLE_OFFSET]; | ||
| 76 | } | ||
| 77 | |||
| 78 | void KernelObjectPool::List() { | ||
| 79 | for (int i = 0; i < MAX_COUNT; i++) { | ||
| 80 | if (occupied[i]) { | ||
| 81 | if (pool[i]) { | ||
| 82 | INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName(), | ||
| 83 | pool[i]->GetName()); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | int KernelObjectPool::GetCount() | ||
| 90 | { | ||
| 91 | int count = 0; | ||
| 92 | for (int i = 0; i < MAX_COUNT; i++) | ||
| 93 | { | ||
| 94 | if (occupied[i]) | ||
| 95 | count++; | ||
| 96 | } | ||
| 97 | return count; | ||
| 98 | } | ||
| 99 | |||
| 100 | KernelObject *KernelObjectPool::CreateByIDType(int type) { | ||
| 101 | // Used for save states. This is ugly, but what other way is there? | ||
| 102 | switch (type) { | ||
| 103 | //case SCE_KERNEL_TMID_Alarm: | ||
| 104 | // return __KernelAlarmObject(); | ||
| 105 | //case SCE_KERNEL_TMID_EventFlag: | ||
| 106 | // return __KernelEventFlagObject(); | ||
| 107 | //case SCE_KERNEL_TMID_Mbox: | ||
| 108 | // return __KernelMbxObject(); | ||
| 109 | //case SCE_KERNEL_TMID_Fpl: | ||
| 110 | // return __KernelMemoryFPLObject(); | ||
| 111 | //case SCE_KERNEL_TMID_Vpl: | ||
| 112 | // return __KernelMemoryVPLObject(); | ||
| 113 | //case PPSSPP_KERNEL_TMID_PMB: | ||
| 114 | // return __KernelMemoryPMBObject(); | ||
| 115 | //case PPSSPP_KERNEL_TMID_Module: | ||
| 116 | // return __KernelModuleObject(); | ||
| 117 | //case SCE_KERNEL_TMID_Mpipe: | ||
| 118 | // return __KernelMsgPipeObject(); | ||
| 119 | //case SCE_KERNEL_TMID_Mutex: | ||
| 120 | // return __KernelMutexObject(); | ||
| 121 | //case SCE_KERNEL_TMID_LwMutex: | ||
| 122 | // return __KernelLwMutexObject(); | ||
| 123 | //case SCE_KERNEL_TMID_Semaphore: | ||
| 124 | // return __KernelSemaphoreObject(); | ||
| 125 | //case SCE_KERNEL_TMID_Callback: | ||
| 126 | // return __KernelCallbackObject(); | ||
| 127 | //case SCE_KERNEL_TMID_Thread: | ||
| 128 | // return __KernelThreadObject(); | ||
| 129 | //case SCE_KERNEL_TMID_VTimer: | ||
| 130 | // return __KernelVTimerObject(); | ||
| 131 | //case SCE_KERNEL_TMID_Tlspl: | ||
| 132 | // return __KernelTlsplObject(); | ||
| 133 | //case PPSSPP_KERNEL_TMID_File: | ||
| 134 | // return __KernelFileNodeObject(); | ||
| 135 | //case PPSSPP_KERNEL_TMID_DirList: | ||
| 136 | // return __KernelDirListingObject(); | ||
| 137 | |||
| 138 | default: | ||
| 139 | ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); | ||
| 140 | return NULL; | ||
| 141 | } | ||
| 142 | } | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h new file mode 100644 index 000000000..2381ca7f7 --- /dev/null +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | typedef u32 UID; | ||
| 10 | |||
| 11 | class KernelObjectPool; | ||
| 12 | |||
| 13 | class KernelObject { | ||
| 14 | friend class KernelObjectPool; | ||
| 15 | u32 uid; | ||
| 16 | public: | ||
| 17 | virtual ~KernelObject() {} | ||
| 18 | UID GetUID() const { return uid; } | ||
| 19 | virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; } | ||
| 20 | virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; } | ||
| 21 | virtual int GetIDType() const = 0; | ||
| 22 | //virtual void GetQuickInfo(char *ptr, int size); | ||
| 23 | }; | ||
| 24 | |||
| 25 | class KernelObjectPool { | ||
| 26 | public: | ||
| 27 | KernelObjectPool(); | ||
| 28 | ~KernelObjectPool() {} | ||
| 29 | |||
| 30 | // Allocates a UID within the range and inserts the object into the map. | ||
| 31 | UID Create(KernelObject *obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); | ||
| 32 | |||
| 33 | static KernelObject *CreateByIDType(int type); | ||
| 34 | |||
| 35 | template <class T> | ||
| 36 | u32 Destroy(UID handle) { | ||
| 37 | u32 error; | ||
| 38 | if (Get<T>(handle, error)) { | ||
| 39 | occupied[handle - handleOffset] = false; | ||
| 40 | delete pool[handle - handleOffset]; | ||
| 41 | } | ||
| 42 | return error; | ||
| 43 | }; | ||
| 44 | |||
| 45 | bool IsValid(UID handle); | ||
| 46 | |||
| 47 | template <class T> | ||
| 48 | T* Get(UID handle, u32& outError) { | ||
| 49 | if (handle < handleOffset || handle >= handleOffset + maxCount || !occupied[handle - handleOffset]) { | ||
| 50 | // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP | ||
| 51 | if (handle != 0 && (u32)handle != 0x80020001) { | ||
| 52 | WARN_LOG(SCEKERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); | ||
| 53 | } | ||
| 54 | outError = T::GetMissingErrorCode(); | ||
| 55 | return 0; | ||
| 56 | } else { | ||
| 57 | // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, | ||
| 58 | // it just acted as a static case and everything worked. This means that we will never | ||
| 59 | // see the Wrong type object error below, but we'll just have to live with that danger. | ||
| 60 | T* t = static_cast<T*>(pool[handle - handleOffset]); | ||
| 61 | if (t == 0 || t->GetIDType() != T::GetStaticIDType()) { | ||
| 62 | WARN_LOG(SCEKERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); | ||
| 63 | outError = T::GetMissingErrorCode(); | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | outError = SCE_KERNEL_ERROR_OK; | ||
| 67 | return t; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | // ONLY use this when you know the handle is valid. | ||
| 72 | template <class T> | ||
| 73 | T *GetFast(UID handle) { | ||
| 74 | const UID realHandle = handle - handleOffset; | ||
| 75 | _dbg_assert_(SCEKERNEL, realHandle >= 0 && realHandle < maxCount && occupied[realHandle]); | ||
| 76 | return static_cast<T *>(pool[realHandle]); | ||
| 77 | } | ||
| 78 | |||
| 79 | template <class T, typename ArgT> | ||
| 80 | void Iterate(bool func(T *, ArgT), ArgT arg) { | ||
| 81 | int type = T::GetStaticIDType(); | ||
| 82 | for (int i = 0; i < maxCount; i++) | ||
| 83 | { | ||
| 84 | if (!occupied[i]) | ||
| 85 | continue; | ||
| 86 | T *t = static_cast<T *>(pool[i]); | ||
| 87 | if (t->GetIDType() == type) { | ||
| 88 | if (!func(t, arg)) | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | bool GetIDType(UID handle, int *type) const { | ||
| 95 | if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || | ||
| 96 | !occupied[handle - HANDLE_OFFSET]) { | ||
| 97 | ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); | ||
| 98 | return false; | ||
| 99 | } | ||
| 100 | KernelObject *t = pool[handle - HANDLE_OFFSET]; | ||
| 101 | *type = t->GetIDType(); | ||
| 102 | return true; | ||
| 103 | } | ||
| 104 | |||
| 105 | KernelObject *&operator [](UID handle); | ||
| 106 | void List(); | ||
| 107 | void Clear(); | ||
| 108 | int GetCount(); | ||
| 109 | |||
| 110 | private: | ||
| 111 | enum { | ||
| 112 | MAX_COUNT = 0x1000, | ||
| 113 | HANDLE_OFFSET = 0x100, | ||
| 114 | INITIAL_NEXT_ID = 0x10, | ||
| 115 | }; | ||
| 116 | KernelObject *pool[MAX_COUNT]; | ||
| 117 | bool occupied[MAX_COUNT]; | ||
| 118 | int next_id; | ||
| 119 | }; | ||
| 120 | |||
| 121 | 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 000000000..0ed35de83 --- /dev/null +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <stdio.h> | ||
| 6 | |||
| 7 | #include <list> | ||
| 8 | #include <vector> | ||
| 9 | #include <map> | ||
| 10 | #include <string> | ||
| 11 | |||
| 12 | #include "common/common.h" | ||
| 13 | |||
| 14 | #include "core/hle/kernel/kernel.h" | ||
| 15 | #include "core/hle/kernel/thread.h" | ||
| 16 | |||
| 17 | // Real CTR struct, don't change the fields. | ||
| 18 | struct NativeThread { | ||
| 19 | //u32 Pointer to vtable | ||
| 20 | //u32 Reference count | ||
| 21 | //KProcess* Process the thread belongs to (virtual address) | ||
| 22 | //u32 Thread id | ||
| 23 | //u32* ptr = *(KThread+0x8C) - 0xB0 | ||
| 24 | //u32* End-address of the page for this thread allocated in the 0xFF4XX000 region. Thus, | ||
| 25 | // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000. | ||
| 26 | //KThread* Previous ? (virtual address) | ||
| 27 | //KThread* Next ? (virtual address) | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct ThreadWaitInfo { | ||
| 31 | u32 wait_value; | ||
| 32 | u32 timeout_ptr; | ||
| 33 | }; | ||
| 34 | |||
| 35 | class Thread : public KernelObject { | ||
| 36 | public: | ||
| 37 | /*const char *GetName() { return nt.name; }*/ | ||
| 38 | const char *GetTypeName() { return "Thread"; } | ||
| 39 | //void GetQuickInfo(char *ptr, int size) | ||
| 40 | //{ | ||
| 41 | // sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )", | ||
| 42 | // context.pc, context.r[13], // 13 is stack pointer | ||
| 43 | // (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "", | ||
| 44 | // (nt.status & THREADSTATUS_READY) ? "READY" : "", | ||
| 45 | // (nt.status & THREADSTATUS_WAIT) ? "WAIT" : "", | ||
| 46 | // (nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "", | ||
| 47 | // (nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "", | ||
| 48 | // (nt.status & THREADSTATUS_DEAD) ? "DEAD" : "", | ||
| 49 | // nt.waitType, | ||
| 50 | // nt.waitID, | ||
| 51 | // waitInfo.waitValue); | ||
| 52 | //} | ||
| 53 | |||
| 54 | //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } | ||
| 55 | //static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; } | ||
| 56 | //int GetIDType() const { return SCE_KERNEL_TMID_Thread; } | ||
| 57 | |||
| 58 | //bool AllocateStack(u32 &stack_size) { | ||
| 59 | // FreeStack(); | ||
| 60 | |||
| 61 | // bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0; | ||
| 62 | // if (nt.attr & PSP_THREAD_ATTR_KERNEL) | ||
| 63 | // { | ||
| 64 | // // Allocate stacks for kernel threads (idle) in kernel RAM | ||
| 65 | // currentStack.start = kernelMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); | ||
| 66 | // } | ||
| 67 | // else | ||
| 68 | // { | ||
| 69 | // currentStack.start = userMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); | ||
| 70 | // } | ||
| 71 | // if (currentStack.start == (u32)-1) | ||
| 72 | // { | ||
| 73 | // currentStack.start = 0; | ||
| 74 | // nt.initialStack = 0; | ||
| 75 | // ERROR_LOG(KERNEL, "Failed to allocate stack for thread"); | ||
| 76 | // return false; | ||
| 77 | // } | ||
| 78 | |||
| 79 | // nt.initialStack = currentStack.start; | ||
| 80 | // nt.stack_size = stack_size; | ||
| 81 | // return true; | ||
| 82 | //} | ||
| 83 | |||
| 84 | //bool FillStack() { | ||
| 85 | // // Fill the stack. | ||
| 86 | // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) { | ||
| 87 | // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); | ||
| 88 | // } | ||
| 89 | // context.r[MIPS_REG_SP] = currentStack.start + nt.stack_size; | ||
| 90 | // currentStack.end = context.r[MIPS_REG_SP]; | ||
| 91 | // // The k0 section is 256 bytes at the top of the stack. | ||
| 92 | // context.r[MIPS_REG_SP] -= 256; | ||
| 93 | // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP]; | ||
| 94 | // u32 k0 = context.r[MIPS_REG_K0]; | ||
| 95 | // Memory::Memset(k0, 0, 0x100); | ||
| 96 | // Memory::Write_U32(GetUID(), k0 + 0xc0); | ||
| 97 | // Memory::Write_U32(nt.initialStack, k0 + 0xc8); | ||
| 98 | // Memory::Write_U32(0xffffffff, k0 + 0xf8); | ||
| 99 | // Memory::Write_U32(0xffffffff, k0 + 0xfc); | ||
| 100 | // // After k0 comes the arguments, which is done by sceKernelStartThread(). | ||
| 101 | |||
| 102 | // Memory::Write_U32(GetUID(), nt.initialStack); | ||
| 103 | // return true; | ||
| 104 | //} | ||
| 105 | |||
| 106 | //void FreeStack() { | ||
| 107 | // if (currentStack.start != 0) { | ||
| 108 | // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name); | ||
| 109 | |||
| 110 | // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) { | ||
| 111 | // Memory::Memset(nt.initialStack, 0, nt.stack_size); | ||
| 112 | // } | ||
| 113 | |||
| 114 | // if (nt.attr & PSP_THREAD_ATTR_KERNEL) { | ||
| 115 | // kernelMemory.Free(currentStack.start); | ||
| 116 | // } | ||
| 117 | // else { | ||
| 118 | // userMemory.Free(currentStack.start); | ||
| 119 | // } | ||
| 120 | // currentStack.start = 0; | ||
| 121 | // } | ||
| 122 | //} | ||
| 123 | |||
| 124 | //bool PushExtendedStack(u32 size) { | ||
| 125 | // u32 stack = userMemory.Alloc(size, true, (std::string("extended/") + nt.name).c_str()); | ||
| 126 | // if (stack == (u32)-1) | ||
| 127 | // return false; | ||
| 128 | |||
| 129 | // pushed_stacks.push_back(currentStack); | ||
| 130 | // currentStack.start = stack; | ||
| 131 | // currentStack.end = stack + size; | ||
| 132 | // nt.initialStack = currentStack.start; | ||
| 133 | // nt.stack_size = currentStack.end - currentStack.start; | ||
| 134 | |||
| 135 | // // We still drop the threadID at the bottom and fill it, but there's no k0. | ||
| 136 | // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); | ||
| 137 | // Memory::Write_U32(GetUID(), nt.initialStack); | ||
| 138 | // return true; | ||
| 139 | //} | ||
| 140 | |||
| 141 | //bool PopExtendedStack() { | ||
| 142 | // if (pushed_stacks.size() == 0) { | ||
| 143 | // return false; | ||
| 144 | // } | ||
| 145 | // userMemory.Free(currentStack.start); | ||
| 146 | // currentStack = pushed_stacks.back(); | ||
| 147 | // pushed_stacks.pop_back(); | ||
| 148 | // nt.initialStack = currentStack.start; | ||
| 149 | // nt.stack_size = currentStack.end - currentStack.start; | ||
| 150 | // return true; | ||
| 151 | //} | ||
| 152 | |||
| 153 | Thread() { | ||
| 154 | currentStack.start = 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | // Can't use a destructor since savestates will call that too. | ||
| 158 | //void Cleanup() { | ||
| 159 | // // Callbacks are automatically deleted when their owning thread is deleted. | ||
| 160 | // for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) | ||
| 161 | // kernelObjects.Destroy<Callback>(*it); | ||
| 162 | |||
| 163 | // if (pushed_stacks.size() != 0) | ||
| 164 | // { | ||
| 165 | // WARN_LOG(KERNEL, "Thread ended within an extended stack"); | ||
| 166 | // for (size_t i = 0; i < pushed_stacks.size(); ++i) | ||
| 167 | // userMemory.Free(pushed_stacks[i].start); | ||
| 168 | // } | ||
| 169 | // FreeStack(); | ||
| 170 | //} | ||
| 171 | |||
| 172 | void setReturnValue(u32 retval); | ||
| 173 | void setReturnValue(u64 retval); | ||
| 174 | void resumeFromWait(); | ||
| 175 | //bool isWaitingFor(WaitType type, int id); | ||
| 176 | //int getWaitID(WaitType type); | ||
| 177 | ThreadWaitInfo getWaitInfo(); | ||
| 178 | |||
| 179 | // Utils | ||
| 180 | //inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } | ||
| 181 | //inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; } | ||
| 182 | //inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; } | ||
| 183 | //inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; } | ||
| 184 | //inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; } | ||
| 185 | |||
| 186 | NativeThread nt; | ||
| 187 | |||
| 188 | ThreadWaitInfo waitInfo; | ||
| 189 | UID moduleId; | ||
| 190 | |||
| 191 | bool isProcessingCallbacks; | ||
| 192 | u32 currentMipscallId; | ||
| 193 | UID currentCallbackId; | ||
| 194 | |||
| 195 | ThreadContext context; | ||
| 196 | |||
| 197 | std::vector<UID> callbacks; | ||
| 198 | |||
| 199 | std::list<u32> pending_calls; | ||
| 200 | |||
| 201 | struct StackInfo { | ||
| 202 | u32 start; | ||
| 203 | u32 end; | ||
| 204 | }; | ||
| 205 | // This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse. | ||
| 206 | // These are stacks that aren't "active" right now, but will pop off once the func returns. | ||
| 207 | std::vector<StackInfo> pushed_stacks; | ||
| 208 | |||
| 209 | StackInfo currentStack; | ||
| 210 | |||
| 211 | // For thread end. | ||
| 212 | std::vector<UID> waiting_threads; | ||
| 213 | // Key is the callback id it was for, or if no callback, the thread id. | ||
| 214 | std::map<UID, u64> paused_waits; | ||
| 215 | }; | ||
| 216 | |||
| 217 | void __KernelThreadingInit() { | ||
| 218 | } | ||
| 219 | |||
| 220 | void __KernelThreadingShutdown() { | ||
| 221 | } | ||
| 222 | |||
| 223 | //const char *__KernelGetThreadName(UID threadID); | ||
| 224 | // | ||
| 225 | //void __KernelSaveContext(ThreadContext *ctx); | ||
| 226 | //void __KernelLoadContext(ThreadContext *ctx); | ||
| 227 | |||
| 228 | //void __KernelSwitchContext(Thread *target, const char *reason); \ No newline at end of file | ||
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h new file mode 100644 index 000000000..c3cdca31f --- /dev/null +++ b/src/core/hle/kernel/thread.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | enum ThreadStatus { | ||
| 10 | THREADSTATUS_RUNNING = 1, | ||
| 11 | THREADSTATUS_READY = 2, | ||
| 12 | THREADSTATUS_WAIT = 4, | ||
| 13 | THREADSTATUS_SUSPEND = 8, | ||
| 14 | THREADSTATUS_DORMANT = 16, | ||
| 15 | THREADSTATUS_DEAD = 32, | ||
| 16 | |||
| 17 | THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND | ||
| 18 | }; | ||
| 19 | |||
| 20 | struct ThreadContext { | ||
| 21 | void reset(); | ||
| 22 | |||
| 23 | u32 reg[16]; | ||
| 24 | u32 cpsr; | ||
| 25 | u32 pc; | ||
| 26 | }; | ||
| 27 | |||
| 28 | void __KernelThreadingInit(); | ||
| 29 | void __KernelThreadingShutdown(); | ||
| 30 | |||
| 31 | //const char *__KernelGetThreadName(SceUID threadID); | ||
| 32 | // | ||
| 33 | //void __KernelSaveContext(ThreadContext *ctx); | ||
| 34 | //void __KernelLoadContext(ThreadContext *ctx); | ||
| 35 | |||
| 36 | //void __KernelSwitchContext(Thread *target, const char *reason); \ No newline at end of file | ||