diff options
| author | 2014-07-08 18:54:12 -0400 | |
|---|---|---|
| committer | 2014-07-08 18:54:12 -0400 | |
| commit | 584f7aced5360654d3f86dd14beb87a637b802f1 (patch) | |
| tree | a4e8761b1b55ca53941db9f2ce8c04f224226238 | |
| parent | Merge pull request #28 from bunnei/shared-memory (diff) | |
| parent | Kernel: Added preliminary support for address arbiters. (diff) | |
| download | yuzu-584f7aced5360654d3f86dd14beb87a637b802f1.tar.gz yuzu-584f7aced5360654d3f86dd14beb87a637b802f1.tar.xz yuzu-584f7aced5360654d3f86dd14beb87a637b802f1.zip | |
Merge pull request #29 from bunnei/address-arbiters
Adds address arbiters to kernel HLE
Diffstat (limited to '')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/core.vcxproj | 2 | ||||
| -rw-r--r-- | src/core/core.vcxproj.filters | 6 | ||||
| -rw-r--r-- | src/core/hle/function_wrappers.h | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 87 | ||||
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.h | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 37 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 7 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 18 |
10 files changed, 197 insertions, 11 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0d3189d29..207f39707 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -34,6 +34,7 @@ set(SRCS core.cpp | |||
| 34 | hle/config_mem.cpp | 34 | hle/config_mem.cpp |
| 35 | hle/coprocessor.cpp | 35 | hle/coprocessor.cpp |
| 36 | hle/svc.cpp | 36 | hle/svc.cpp |
| 37 | hle/kernel/address_arbiter.cpp | ||
| 37 | hle/kernel/archive.cpp | 38 | hle/kernel/archive.cpp |
| 38 | hle/kernel/event.cpp | 39 | hle/kernel/event.cpp |
| 39 | hle/kernel/kernel.cpp | 40 | hle/kernel/kernel.cpp |
| @@ -83,6 +84,7 @@ set(HEADERS core.h | |||
| 83 | hle/coprocessor.h | 84 | hle/coprocessor.h |
| 84 | hle/hle.h | 85 | hle/hle.h |
| 85 | hle/svc.h | 86 | hle/svc.h |
| 87 | hle/kernel/address_arbiter.h | ||
| 86 | hle/kernel/archive.h | 88 | hle/kernel/archive.h |
| 87 | hle/kernel/kernel.h | 89 | hle/kernel/kernel.h |
| 88 | hle/kernel/mutex.h | 90 | hle/kernel/mutex.h |
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index a09a4a1f1..ddc174c2c 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj | |||
| @@ -166,6 +166,7 @@ | |||
| 166 | <ClCompile Include="hle\config_mem.cpp" /> | 166 | <ClCompile Include="hle\config_mem.cpp" /> |
| 167 | <ClCompile Include="hle\coprocessor.cpp" /> | 167 | <ClCompile Include="hle\coprocessor.cpp" /> |
| 168 | <ClCompile Include="hle\hle.cpp" /> | 168 | <ClCompile Include="hle\hle.cpp" /> |
| 169 | <ClCompile Include="hle\kernel\address_arbiter.cpp" /> | ||
| 169 | <ClCompile Include="hle\kernel\archive.cpp" /> | 170 | <ClCompile Include="hle\kernel\archive.cpp" /> |
| 170 | <ClCompile Include="hle\kernel\event.cpp" /> | 171 | <ClCompile Include="hle\kernel\event.cpp" /> |
| 171 | <ClCompile Include="hle\kernel\kernel.cpp" /> | 172 | <ClCompile Include="hle\kernel\kernel.cpp" /> |
| @@ -219,6 +220,7 @@ | |||
| 219 | <ClInclude Include="hle\coprocessor.h" /> | 220 | <ClInclude Include="hle\coprocessor.h" /> |
| 220 | <ClInclude Include="hle\function_wrappers.h" /> | 221 | <ClInclude Include="hle\function_wrappers.h" /> |
| 221 | <ClInclude Include="hle\hle.h" /> | 222 | <ClInclude Include="hle\hle.h" /> |
| 223 | <ClInclude Include="hle\kernel\address_arbiter.h" /> | ||
| 222 | <ClInclude Include="hle\kernel\archive.h" /> | 224 | <ClInclude Include="hle\kernel\archive.h" /> |
| 223 | <ClInclude Include="hle\kernel\event.h" /> | 225 | <ClInclude Include="hle\kernel\event.h" /> |
| 224 | <ClInclude Include="hle\kernel\kernel.h" /> | 226 | <ClInclude Include="hle\kernel\kernel.h" /> |
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 7e6a7f91b..68ba9e50b 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters | |||
| @@ -182,6 +182,9 @@ | |||
| 182 | <ClCompile Include="hle\kernel\shared_memory.cpp"> | 182 | <ClCompile Include="hle\kernel\shared_memory.cpp"> |
| 183 | <Filter>hle\kernel</Filter> | 183 | <Filter>hle\kernel</Filter> |
| 184 | </ClCompile> | 184 | </ClCompile> |
| 185 | <ClCompile Include="hle\kernel\address_arbiter.cpp"> | ||
| 186 | <Filter>hle\kernel</Filter> | ||
| 187 | </ClCompile> | ||
| 185 | </ItemGroup> | 188 | </ItemGroup> |
| 186 | <ItemGroup> | 189 | <ItemGroup> |
| 187 | <ClInclude Include="arm\disassembler\arm_disasm.h"> | 190 | <ClInclude Include="arm\disassembler\arm_disasm.h"> |
| @@ -326,6 +329,9 @@ | |||
| 326 | <ClInclude Include="hle\kernel\shared_memory.h"> | 329 | <ClInclude Include="hle\kernel\shared_memory.h"> |
| 327 | <Filter>hle\kernel</Filter> | 330 | <Filter>hle\kernel</Filter> |
| 328 | </ClInclude> | 331 | </ClInclude> |
| 332 | <ClInclude Include="hle\kernel\address_arbiter.h"> | ||
| 333 | <Filter>hle\kernel</Filter> | ||
| 334 | </ClInclude> | ||
| 329 | </ItemGroup> | 335 | </ItemGroup> |
| 330 | <ItemGroup> | 336 | <ItemGroup> |
| 331 | <Text Include="CMakeLists.txt" /> | 337 | <Text Include="CMakeLists.txt" /> |
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 0bed78653..ea603a1bb 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -39,9 +39,16 @@ template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() { | |||
| 39 | RETURN(retval); | 39 | RETURN(retval); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | // TODO(bunnei): Is this correct? Probably not | 42 | // TODO(bunnei): Is this correct? Probably not - Last parameter looks wrong for ArbitrateAddress |
| 43 | template<s32 func(u32, u32, u32, u32, s64)> void Wrap() { | 43 | template<s32 func(u32, u32, u32, u32, s64)> void Wrap() { |
| 44 | RETURN(func(PARAM(5), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(4) << 32) | PARAM(0)))); | 44 | RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4)))); |
| 45 | } | ||
| 46 | |||
| 47 | template<s32 func(u32*)> void Wrap(){ | ||
| 48 | u32 param_1 = 0; | ||
| 49 | u32 retval = func(¶m_1); | ||
| 50 | Core::g_app_core->SetReg(1, param_1); | ||
| 51 | RETURN(retval); | ||
| 45 | } | 52 | } |
| 46 | 53 | ||
| 47 | template<s32 func(u32, s64)> void Wrap() { | 54 | template<s32 func(u32, s64)> void Wrap() { |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp new file mode 100644 index 000000000..61717bbe4 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | |||
| 7 | #include "core/mem_map.h" | ||
| 8 | |||
| 9 | #include "core/hle/hle.h" | ||
| 10 | #include "core/hle/kernel/address_arbiter.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // Kernel namespace | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | |||
| 18 | class AddressArbiter : public Object { | ||
| 19 | public: | ||
| 20 | const char* GetTypeName() const { return "Arbiter"; } | ||
| 21 | const char* GetName() const { return name.c_str(); } | ||
| 22 | |||
| 23 | static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; } | ||
| 24 | Kernel::HandleType GetHandleType() const { return HandleType::AddressArbiter; } | ||
| 25 | |||
| 26 | std::string name; ///< Name of address arbiter object (optional) | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Wait for kernel object to synchronize | ||
| 30 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 31 | * @return Result of operation, 0 on success, otherwise error code | ||
| 32 | */ | ||
| 33 | Result WaitSynchronization(bool* wait) { | ||
| 34 | // TODO(bunnei): ImplementMe | ||
| 35 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | }; | ||
| 39 | |||
| 40 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 41 | |||
| 42 | /// Arbitrate an address | ||
| 43 | Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { | ||
| 44 | switch (type) { | ||
| 45 | |||
| 46 | // Signal thread(s) waiting for arbitrate address... | ||
| 47 | case ArbitrationType::Signal: | ||
| 48 | // Negative value means resume all threads | ||
| 49 | if (value < 0) { | ||
| 50 | ArbitrateAllThreads(handle, address); | ||
| 51 | } else { | ||
| 52 | // Resume first N threads | ||
| 53 | for(int i = 0; i < value; i++) | ||
| 54 | ArbitrateHighestPriorityThread(handle, address); | ||
| 55 | } | ||
| 56 | HLE::Reschedule(__func__); | ||
| 57 | |||
| 58 | // Wait current thread (acquire the arbiter)... | ||
| 59 | case ArbitrationType::WaitIfLessThan: | ||
| 60 | if ((s32)Memory::Read32(address) <= value) { | ||
| 61 | Kernel::WaitCurrentThread(WAITTYPE_ARB, handle); | ||
| 62 | HLE::Reschedule(__func__); | ||
| 63 | } | ||
| 64 | |||
| 65 | default: | ||
| 66 | ERROR_LOG(KERNEL, "unknown type=%d", type); | ||
| 67 | return -1; | ||
| 68 | } | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | /// Create an address arbiter | ||
| 73 | AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) { | ||
| 74 | AddressArbiter* address_arbiter = new AddressArbiter; | ||
| 75 | handle = Kernel::g_object_pool.Create(address_arbiter); | ||
| 76 | address_arbiter->name = name; | ||
| 77 | return address_arbiter; | ||
| 78 | } | ||
| 79 | |||
| 80 | /// Create an address arbiter | ||
| 81 | Handle CreateAddressArbiter(const std::string& name) { | ||
| 82 | Handle handle; | ||
| 83 | CreateAddressArbiter(handle, name); | ||
| 84 | return handle; | ||
| 85 | } | ||
| 86 | |||
| 87 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h new file mode 100644 index 000000000..a483fe466 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | // Copyright 2014 Citra Emulator 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 | #include "core/hle/kernel/kernel.h" | ||
| 10 | |||
| 11 | // Address arbiters are an underlying kernel synchronization object that can be created/used via | ||
| 12 | // supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR | ||
| 13 | // applications use them as an underlying mechanism to implement thread-safe barriers, events, and | ||
| 14 | // semphores. | ||
| 15 | |||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 17 | // Kernel namespace | ||
| 18 | |||
| 19 | namespace Kernel { | ||
| 20 | |||
| 21 | /// Address arbitration types | ||
| 22 | enum class ArbitrationType : u32 { | ||
| 23 | Signal, | ||
| 24 | WaitIfLessThan, | ||
| 25 | DecrementAndWaitIfLessThan, | ||
| 26 | WaitIfLessThanWithTimeout, | ||
| 27 | DecrementAndWaitIfLessThanWithTimeout, | ||
| 28 | }; | ||
| 29 | |||
| 30 | /// Arbitrate an address | ||
| 31 | Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); | ||
| 32 | |||
| 33 | /// Create an address arbiter | ||
| 34 | Handle CreateAddressArbiter(const std::string& name = "Unknown"); | ||
| 35 | |||
| 36 | } // namespace FileSys | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 69f4ddd37..d9afcdd25 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -26,7 +26,7 @@ enum class HandleType : u32 { | |||
| 26 | Redirection = 6, | 26 | Redirection = 6, |
| 27 | Thread = 7, | 27 | Thread = 7, |
| 28 | Process = 8, | 28 | Process = 8, |
| 29 | Arbiter = 9, | 29 | AddressArbiter = 9, |
| 30 | File = 10, | 30 | File = 10, |
| 31 | Semaphore = 11, | 31 | Semaphore = 11, |
| 32 | Archive = 12, | 32 | Archive = 12, |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ab5a5559e..86bbf29d0 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -188,6 +188,43 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { | |||
| 188 | } | 188 | } |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | /// Arbitrate the highest priority thread that is waiting | ||
| 192 | Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | ||
| 193 | Handle highest_priority_thread = 0; | ||
| 194 | s32 priority = THREADPRIO_LOWEST; | ||
| 195 | |||
| 196 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | ||
| 197 | for (const auto& handle : g_thread_queue) { | ||
| 198 | |||
| 199 | // TODO(bunnei): Verify arbiter address... | ||
| 200 | if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) | ||
| 201 | continue; | ||
| 202 | |||
| 203 | Thread* thread = g_object_pool.GetFast<Thread>(handle); | ||
| 204 | if(thread->current_priority <= priority) { | ||
| 205 | highest_priority_thread = handle; | ||
| 206 | priority = thread->current_priority; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | // If a thread was arbitrated, resume it | ||
| 210 | if (0 != highest_priority_thread) | ||
| 211 | ResumeThreadFromWait(highest_priority_thread); | ||
| 212 | |||
| 213 | return highest_priority_thread; | ||
| 214 | } | ||
| 215 | |||
| 216 | /// Arbitrate all threads currently waiting | ||
| 217 | void ArbitrateAllThreads(u32 arbiter, u32 address) { | ||
| 218 | |||
| 219 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | ||
| 220 | for (const auto& handle : g_thread_queue) { | ||
| 221 | |||
| 222 | // TODO(bunnei): Verify arbiter address... | ||
| 223 | if (VerifyWait(handle, WAITTYPE_ARB, arbiter)) | ||
| 224 | ResumeThreadFromWait(handle); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 191 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) | 228 | /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) |
| 192 | void CallThread(Thread* t) { | 229 | void CallThread(Thread* t) { |
| 193 | // Stop waiting | 230 | // Stop waiting |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 04914ba90..f2bfdfa1a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -39,6 +39,7 @@ enum WaitType { | |||
| 39 | WAITTYPE_VBLANK, | 39 | WAITTYPE_VBLANK, |
| 40 | WAITTYPE_MUTEX, | 40 | WAITTYPE_MUTEX, |
| 41 | WAITTYPE_SYNCH, | 41 | WAITTYPE_SYNCH, |
| 42 | WAITTYPE_ARB, | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | namespace Kernel { | 45 | namespace Kernel { |
| @@ -59,6 +60,12 @@ void StopThread(Handle thread, const char* reason); | |||
| 59 | /// Resumes a thread from waiting by marking it as "ready" | 60 | /// Resumes a thread from waiting by marking it as "ready" |
| 60 | void ResumeThreadFromWait(Handle handle); | 61 | void ResumeThreadFromWait(Handle handle); |
| 61 | 62 | ||
| 63 | /// Arbitrate the highest priority thread that is waiting | ||
| 64 | Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address); | ||
| 65 | |||
| 66 | /// Arbitrate all threads currently waiting... | ||
| 67 | void ArbitrateAllThreads(u32 arbiter, u32 address); | ||
| 68 | |||
| 62 | /// Gets the current thread handle | 69 | /// Gets the current thread handle |
| 63 | Handle GetCurrentThreadHandle(); | 70 | Handle GetCurrentThreadHandle(); |
| 64 | 71 | ||
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 9130d77ec..17967f260 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "core/mem_map.h" | 10 | #include "core/mem_map.h" |
| 11 | 11 | ||
| 12 | #include "core/hle/kernel/address_arbiter.h" | ||
| 12 | #include "core/hle/kernel/event.h" | 13 | #include "core/hle/kernel/event.h" |
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/mutex.h" | 15 | #include "core/hle/kernel/mutex.h" |
| @@ -175,18 +176,19 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa | |||
| 175 | } | 176 | } |
| 176 | 177 | ||
| 177 | /// Create an address arbiter (to allocate access to shared resources) | 178 | /// Create an address arbiter (to allocate access to shared resources) |
| 178 | Result CreateAddressArbiter(void* arbiter) { | 179 | Result CreateAddressArbiter(u32* arbiter) { |
| 179 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called"); | 180 | DEBUG_LOG(SVC, "called"); |
| 180 | Core::g_app_core->SetReg(1, 0xFABBDADD); | 181 | Handle handle = Kernel::CreateAddressArbiter(); |
| 182 | *arbiter = handle; | ||
| 181 | return 0; | 183 | return 0; |
| 182 | } | 184 | } |
| 183 | 185 | ||
| 184 | /// Arbitrate address | 186 | /// Arbitrate address |
| 185 | Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) { | 187 | Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { |
| 186 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called"); | 188 | DEBUG_LOG(SVC, "called arbiter=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X, " |
| 187 | ArbitrationType type = (ArbitrationType)_type; | 189 | "nanoseconds=%d", arbiter, address, type, value, nanoseconds); |
| 188 | Memory::Write32(addr, type); | 190 | return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), address, |
| 189 | return 0; | 191 | value); |
| 190 | } | 192 | } |
| 191 | 193 | ||
| 192 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | 194 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit |