added initial kernel/thread modules
This commit is contained in:
		| @@ -22,6 +22,8 @@ set(SRCS    core.cpp | |||||||
|             hle/config_mem.cpp |             hle/config_mem.cpp | ||||||
|             hle/coprocessor.cpp |             hle/coprocessor.cpp | ||||||
|             hle/syscall.cpp |             hle/syscall.cpp | ||||||
|  |             hle/kernel/kernel.cpp | ||||||
|  |             hle/kernel/thread.cpp | ||||||
|             hle/service/apt.cpp |             hle/service/apt.cpp | ||||||
|             hle/service/gsp.cpp |             hle/service/gsp.cpp | ||||||
|             hle/service/hid.cpp |             hle/service/hid.cpp | ||||||
|   | |||||||
| @@ -156,6 +156,8 @@ | |||||||
|     <ClCompile Include="hle\config_mem.cpp" /> |     <ClCompile Include="hle\config_mem.cpp" /> | ||||||
|     <ClCompile Include="hle\coprocessor.cpp" /> |     <ClCompile Include="hle\coprocessor.cpp" /> | ||||||
|     <ClCompile Include="hle\hle.cpp" /> |     <ClCompile Include="hle\hle.cpp" /> | ||||||
|  |     <ClCompile Include="hle\kernel\kernel.cpp" /> | ||||||
|  |     <ClCompile Include="hle\kernel\thread.cpp" /> | ||||||
|     <ClCompile Include="hle\service\apt.cpp" /> |     <ClCompile Include="hle\service\apt.cpp" /> | ||||||
|     <ClCompile Include="hle\service\gsp.cpp" /> |     <ClCompile Include="hle\service\gsp.cpp" /> | ||||||
|     <ClCompile Include="hle\service\hid.cpp" /> |     <ClCompile Include="hle\service\hid.cpp" /> | ||||||
| @@ -198,6 +200,8 @@ | |||||||
|     <ClInclude Include="hle\coprocessor.h" /> |     <ClInclude Include="hle\coprocessor.h" /> | ||||||
|     <ClInclude Include="hle\function_wrappers.h" /> |     <ClInclude Include="hle\function_wrappers.h" /> | ||||||
|     <ClInclude Include="hle\hle.h" /> |     <ClInclude Include="hle\hle.h" /> | ||||||
|  |     <ClInclude Include="hle\kernel\kernel.h" /> | ||||||
|  |     <ClInclude Include="hle\kernel\thread.h" /> | ||||||
|     <ClInclude Include="hle\service\apt.h" /> |     <ClInclude Include="hle\service\apt.h" /> | ||||||
|     <ClInclude Include="hle\service\gsp.h" /> |     <ClInclude Include="hle\service\gsp.h" /> | ||||||
|     <ClInclude Include="hle\service\hid.h" /> |     <ClInclude Include="hle\service\hid.h" /> | ||||||
|   | |||||||
| @@ -28,6 +28,9 @@ | |||||||
|     <Filter Include="hle\service"> |     <Filter Include="hle\service"> | ||||||
|       <UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier> |       <UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier> | ||||||
|     </Filter> |     </Filter> | ||||||
|  |     <Filter Include="hle\kernel"> | ||||||
|  |       <UniqueIdentifier>{f2b132eb-caff-4b04-aaae-88d24393a711}</UniqueIdentifier> | ||||||
|  |     </Filter> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="arm\disassembler\arm_disasm.cpp"> |     <ClCompile Include="arm\disassembler\arm_disasm.cpp"> | ||||||
| @@ -114,6 +117,12 @@ | |||||||
|     <ClCompile Include="hle\config_mem.cpp"> |     <ClCompile Include="hle\config_mem.cpp"> | ||||||
|       <Filter>hle</Filter> |       <Filter>hle</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="hle\kernel\thread.cpp"> | ||||||
|  |       <Filter>hle\kernel</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="hle\kernel\kernel.cpp"> | ||||||
|  |       <Filter>hle\kernel</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClInclude Include="arm\disassembler\arm_disasm.h"> |     <ClInclude Include="arm\disassembler\arm_disasm.h"> | ||||||
| @@ -223,6 +232,12 @@ | |||||||
|     <ClInclude Include="hle\config_mem.h"> |     <ClInclude Include="hle\config_mem.h"> | ||||||
|       <Filter>hle</Filter> |       <Filter>hle</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="hle\kernel\thread.h"> | ||||||
|  |       <Filter>hle\kernel</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="hle\kernel\kernel.h"> | ||||||
|  |       <Filter>hle\kernel</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Text Include="CMakeLists.txt" /> |     <Text Include="CMakeLists.txt" /> | ||||||
|   | |||||||
							
								
								
									
										142
									
								
								src/core/hle/kernel/kernel.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/core/hle/kernel/kernel.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | |||||||
|  | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||||||
|  | // Licensed under GPLv2 | ||||||
|  | // Refer to the license.txt file included.   | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #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; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										121
									
								
								src/core/hle/kernel/kernel.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/core/hle/kernel/kernel.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <class T> | ||||||
|  |     u32 Destroy(UID handle) { | ||||||
|  |         u32 error; | ||||||
|  |         if (Get<T>(handle, error)) { | ||||||
|  |             occupied[handle - handleOffset] = false; | ||||||
|  |             delete pool[handle - handleOffset]; | ||||||
|  |         } | ||||||
|  |         return error; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     bool IsValid(UID handle); | ||||||
|  |  | ||||||
|  |     template <class T> | ||||||
|  |     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<T*>(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 <class T> | ||||||
|  |     T *GetFast(UID handle) { | ||||||
|  |         const UID realHandle = handle - handleOffset; | ||||||
|  |         _dbg_assert_(SCEKERNEL, realHandle >= 0 && realHandle < maxCount && occupied[realHandle]); | ||||||
|  |         return static_cast<T *>(pool[realHandle]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template <class T, typename ArgT> | ||||||
|  |     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<T *>(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; | ||||||
							
								
								
									
										228
									
								
								src/core/hle/kernel/thread.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/core/hle/kernel/thread.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | |||||||
|  | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||||||
|  | // Licensed under GPLv2 | ||||||
|  | // Refer to the license.txt file included.   | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | #include <list> | ||||||
|  | #include <vector> | ||||||
|  | #include <map> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | #include "common/common.h" | ||||||
|  |  | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
|  |  | ||||||
|  | // Real CTR struct, don't change the fields. | ||||||
|  | struct NativeThread { | ||||||
|  |     //u32         Pointer to vtable | ||||||
|  |     //u32         Reference count | ||||||
|  |     //KProcess*   Process the thread belongs to (virtual address) | ||||||
|  |     //u32         Thread id | ||||||
|  |     //u32*        ptr = *(KThread+0x8C) - 0xB0 | ||||||
|  |     //u32*        End-address of the page for this thread allocated in the 0xFF4XX000 region. Thus,  | ||||||
|  |     //      if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000. | ||||||
|  |     //KThread*    Previous ? (virtual address) | ||||||
|  |     //KThread*    Next ? (virtual address) | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct ThreadWaitInfo { | ||||||
|  |     u32 wait_value; | ||||||
|  |     u32 timeout_ptr; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class Thread : public KernelObject { | ||||||
|  | public: | ||||||
|  |     /*const char *GetName() { return nt.name; }*/ | ||||||
|  |     const char *GetTypeName() { return "Thread"; } | ||||||
|  |     //void GetQuickInfo(char *ptr, int size) | ||||||
|  |     //{ | ||||||
|  |     //    sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )", | ||||||
|  |     //        context.pc, context.r[13], // 13 is stack pointer | ||||||
|  |     //        (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "", | ||||||
|  |     //        (nt.status & THREADSTATUS_READY) ? "READY" : "", | ||||||
|  |     //        (nt.status & THREADSTATUS_WAIT) ? "WAIT" : "", | ||||||
|  |     //        (nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "", | ||||||
|  |     //        (nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "", | ||||||
|  |     //        (nt.status & THREADSTATUS_DEAD) ? "DEAD" : "", | ||||||
|  |     //        nt.waitType, | ||||||
|  |     //        nt.waitID, | ||||||
|  |     //        waitInfo.waitValue); | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } | ||||||
|  |     //static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; } | ||||||
|  |     //int GetIDType() const { return SCE_KERNEL_TMID_Thread; } | ||||||
|  |  | ||||||
|  |     //bool AllocateStack(u32 &stack_size) { | ||||||
|  |     //    FreeStack(); | ||||||
|  |  | ||||||
|  |     //    bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0; | ||||||
|  |     //    if (nt.attr & PSP_THREAD_ATTR_KERNEL) | ||||||
|  |     //    { | ||||||
|  |     //        // Allocate stacks for kernel threads (idle) in kernel RAM | ||||||
|  |     //        currentStack.start = kernelMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); | ||||||
|  |     //    } | ||||||
|  |     //    else | ||||||
|  |     //    { | ||||||
|  |     //        currentStack.start = userMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); | ||||||
|  |     //    } | ||||||
|  |     //    if (currentStack.start == (u32)-1) | ||||||
|  |     //    { | ||||||
|  |     //        currentStack.start = 0; | ||||||
|  |     //        nt.initialStack = 0; | ||||||
|  |     //        ERROR_LOG(KERNEL, "Failed to allocate stack for thread"); | ||||||
|  |     //        return false; | ||||||
|  |     //    } | ||||||
|  |  | ||||||
|  |     //    nt.initialStack = currentStack.start; | ||||||
|  |     //    nt.stack_size = stack_size; | ||||||
|  |     //    return true; | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     //bool FillStack() { | ||||||
|  |     //    // Fill the stack. | ||||||
|  |     //    if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) { | ||||||
|  |     //        Memory::Memset(currentStack.start, 0xFF, nt.stack_size); | ||||||
|  |     //    } | ||||||
|  |     //    context.r[MIPS_REG_SP] = currentStack.start + nt.stack_size; | ||||||
|  |     //    currentStack.end = context.r[MIPS_REG_SP]; | ||||||
|  |     //    // The k0 section is 256 bytes at the top of the stack. | ||||||
|  |     //    context.r[MIPS_REG_SP] -= 256; | ||||||
|  |     //    context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP]; | ||||||
|  |     //    u32 k0 = context.r[MIPS_REG_K0]; | ||||||
|  |     //    Memory::Memset(k0, 0, 0x100); | ||||||
|  |     //    Memory::Write_U32(GetUID(), k0 + 0xc0); | ||||||
|  |     //    Memory::Write_U32(nt.initialStack, k0 + 0xc8); | ||||||
|  |     //    Memory::Write_U32(0xffffffff, k0 + 0xf8); | ||||||
|  |     //    Memory::Write_U32(0xffffffff, k0 + 0xfc); | ||||||
|  |     //    // After k0 comes the arguments, which is done by sceKernelStartThread(). | ||||||
|  |  | ||||||
|  |     //    Memory::Write_U32(GetUID(), nt.initialStack); | ||||||
|  |     //    return true; | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     //void FreeStack() { | ||||||
|  |     //    if (currentStack.start != 0) { | ||||||
|  |     //        DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name); | ||||||
|  |  | ||||||
|  |     //        if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) { | ||||||
|  |     //            Memory::Memset(nt.initialStack, 0, nt.stack_size); | ||||||
|  |     //        } | ||||||
|  |  | ||||||
|  |     //        if (nt.attr & PSP_THREAD_ATTR_KERNEL) { | ||||||
|  |     //            kernelMemory.Free(currentStack.start); | ||||||
|  |     //        } | ||||||
|  |     //        else { | ||||||
|  |     //            userMemory.Free(currentStack.start); | ||||||
|  |     //        } | ||||||
|  |     //        currentStack.start = 0; | ||||||
|  |     //    } | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     //bool PushExtendedStack(u32 size) { | ||||||
|  |     //    u32 stack = userMemory.Alloc(size, true, (std::string("extended/") + nt.name).c_str()); | ||||||
|  |     //    if (stack == (u32)-1) | ||||||
|  |     //        return false; | ||||||
|  |  | ||||||
|  |     //    pushed_stacks.push_back(currentStack); | ||||||
|  |     //    currentStack.start = stack; | ||||||
|  |     //    currentStack.end = stack + size; | ||||||
|  |     //    nt.initialStack = currentStack.start; | ||||||
|  |     //    nt.stack_size = currentStack.end - currentStack.start; | ||||||
|  |  | ||||||
|  |     //    // We still drop the threadID at the bottom and fill it, but there's no k0. | ||||||
|  |     //    Memory::Memset(currentStack.start, 0xFF, nt.stack_size); | ||||||
|  |     //    Memory::Write_U32(GetUID(), nt.initialStack); | ||||||
|  |     //    return true; | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     //bool PopExtendedStack() { | ||||||
|  |     //    if (pushed_stacks.size() == 0) { | ||||||
|  |     //        return false; | ||||||
|  |     //    } | ||||||
|  |     //    userMemory.Free(currentStack.start); | ||||||
|  |     //    currentStack = pushed_stacks.back(); | ||||||
|  |     //    pushed_stacks.pop_back(); | ||||||
|  |     //    nt.initialStack = currentStack.start; | ||||||
|  |     //    nt.stack_size = currentStack.end - currentStack.start; | ||||||
|  |     //    return true; | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     Thread() { | ||||||
|  |         currentStack.start = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Can't use a destructor since savestates will call that too. | ||||||
|  |     //void Cleanup() { | ||||||
|  |     //    // Callbacks are automatically deleted when their owning thread is deleted. | ||||||
|  |     //    for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) | ||||||
|  |     //        kernelObjects.Destroy<Callback>(*it); | ||||||
|  |  | ||||||
|  |     //    if (pushed_stacks.size() != 0) | ||||||
|  |     //    { | ||||||
|  |     //        WARN_LOG(KERNEL, "Thread ended within an extended stack"); | ||||||
|  |     //        for (size_t i = 0; i < pushed_stacks.size(); ++i) | ||||||
|  |     //            userMemory.Free(pushed_stacks[i].start); | ||||||
|  |     //    } | ||||||
|  |     //    FreeStack(); | ||||||
|  |     //} | ||||||
|  |  | ||||||
|  |     void setReturnValue(u32 retval); | ||||||
|  |     void setReturnValue(u64 retval); | ||||||
|  |     void resumeFromWait(); | ||||||
|  |     //bool isWaitingFor(WaitType type, int id); | ||||||
|  |     //int getWaitID(WaitType type); | ||||||
|  |     ThreadWaitInfo getWaitInfo(); | ||||||
|  |  | ||||||
|  |     // Utils | ||||||
|  |     //inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } | ||||||
|  |     //inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; } | ||||||
|  |     //inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; } | ||||||
|  |     //inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; } | ||||||
|  |     //inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; } | ||||||
|  |  | ||||||
|  |     NativeThread nt; | ||||||
|  |  | ||||||
|  |     ThreadWaitInfo waitInfo; | ||||||
|  |     UID moduleId; | ||||||
|  |  | ||||||
|  |     bool isProcessingCallbacks; | ||||||
|  |     u32 currentMipscallId; | ||||||
|  |     UID currentCallbackId; | ||||||
|  |  | ||||||
|  |     ThreadContext context; | ||||||
|  |  | ||||||
|  |     std::vector<UID> callbacks; | ||||||
|  |  | ||||||
|  |     std::list<u32> pending_calls; | ||||||
|  |  | ||||||
|  |     struct StackInfo { | ||||||
|  |         u32 start; | ||||||
|  |         u32 end; | ||||||
|  |     }; | ||||||
|  |     // This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse. | ||||||
|  |     // These are stacks that aren't "active" right now, but will pop off once the func returns. | ||||||
|  |     std::vector<StackInfo> pushed_stacks; | ||||||
|  |  | ||||||
|  |     StackInfo currentStack; | ||||||
|  |  | ||||||
|  |     // For thread end. | ||||||
|  |     std::vector<UID> waiting_threads; | ||||||
|  |     // Key is the callback id it was for, or if no callback, the thread id. | ||||||
|  |     std::map<UID, u64> paused_waits; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void __KernelThreadingInit() { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void __KernelThreadingShutdown() { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //const char *__KernelGetThreadName(UID threadID); | ||||||
|  | // | ||||||
|  | //void __KernelSaveContext(ThreadContext *ctx); | ||||||
|  | //void __KernelLoadContext(ThreadContext *ctx); | ||||||
|  |  | ||||||
|  | //void __KernelSwitchContext(Thread *target, const char *reason); | ||||||
							
								
								
									
										36
									
								
								src/core/hle/kernel/thread.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/core/hle/kernel/thread.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||||||
|  | // Licensed under GPLv2 | ||||||
|  | // Refer to the license.txt file included.   | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "common/common_types.h" | ||||||
|  |  | ||||||
|  | enum ThreadStatus { | ||||||
|  |     THREADSTATUS_RUNNING = 1, | ||||||
|  |     THREADSTATUS_READY = 2, | ||||||
|  |     THREADSTATUS_WAIT = 4, | ||||||
|  |     THREADSTATUS_SUSPEND = 8, | ||||||
|  |     THREADSTATUS_DORMANT = 16, | ||||||
|  |     THREADSTATUS_DEAD = 32, | ||||||
|  |  | ||||||
|  |     THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct ThreadContext { | ||||||
|  |     void reset(); | ||||||
|  |  | ||||||
|  |     u32 reg[16]; | ||||||
|  |     u32 cpsr; | ||||||
|  |     u32 pc; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void __KernelThreadingInit(); | ||||||
|  | void __KernelThreadingShutdown(); | ||||||
|  |  | ||||||
|  | //const char *__KernelGetThreadName(SceUID threadID); | ||||||
|  | // | ||||||
|  | //void __KernelSaveContext(ThreadContext *ctx); | ||||||
|  | //void __KernelLoadContext(ThreadContext *ctx); | ||||||
|  |  | ||||||
|  | //void __KernelSwitchContext(Thread *target, const char *reason); | ||||||
		Reference in New Issue
	
	Block a user