k_handle_table.h 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <array>
  5. #include "common/assert.h"
  6. #include "common/bit_field.h"
  7. #include "common/common_types.h"
  8. #include "core/hle/kernel/k_auto_object.h"
  9. #include "core/hle/kernel/k_spin_lock.h"
  10. #include "core/hle/kernel/k_thread.h"
  11. #include "core/hle/kernel/kernel.h"
  12. #include "core/hle/kernel/svc_common.h"
  13. #include "core/hle/kernel/svc_results.h"
  14. #include "core/hle/result.h"
  15. namespace Kernel {
  16. class KernelCore;
  17. class KHandleTable {
  18. YUZU_NON_COPYABLE(KHandleTable);
  19. YUZU_NON_MOVEABLE(KHandleTable);
  20. public:
  21. static constexpr size_t MaxTableSize = 1024;
  22. public:
  23. explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
  24. Result Initialize(s32 size) {
  25. // Check that the table size is valid.
  26. R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
  27. // Lock.
  28. KScopedDisableDispatch dd{m_kernel};
  29. KScopedSpinLock lk(m_lock);
  30. // Initialize all fields.
  31. m_max_count = 0;
  32. m_table_size = static_cast<s16>((size <= 0) ? MaxTableSize : size);
  33. m_next_linear_id = MinLinearId;
  34. m_count = 0;
  35. m_free_head_index = -1;
  36. // Free all entries.
  37. for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
  38. m_objects[i] = nullptr;
  39. m_entry_infos[i].next_free_index = static_cast<s16>(i - 1);
  40. m_free_head_index = i;
  41. }
  42. R_SUCCEED();
  43. }
  44. size_t GetTableSize() const {
  45. return m_table_size;
  46. }
  47. size_t GetCount() const {
  48. return m_count;
  49. }
  50. size_t GetMaxCount() const {
  51. return m_max_count;
  52. }
  53. Result Finalize();
  54. bool Remove(Handle handle);
  55. template <typename T = KAutoObject>
  56. KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
  57. // Lock and look up in table.
  58. KScopedDisableDispatch dd{m_kernel};
  59. KScopedSpinLock lk(m_lock);
  60. if constexpr (std::is_same_v<T, KAutoObject>) {
  61. return this->GetObjectImpl(handle);
  62. } else {
  63. if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) [[likely]] {
  64. return obj->DynamicCast<T*>();
  65. } else {
  66. return nullptr;
  67. }
  68. }
  69. }
  70. template <typename T = KAutoObject>
  71. KScopedAutoObject<T> GetObject(Handle handle) const {
  72. // Handle pseudo-handles.
  73. if constexpr (std::derived_from<KProcess, T>) {
  74. if (handle == Svc::PseudoHandle::CurrentProcess) {
  75. //! FIXME: this is the wrong process!
  76. auto* const cur_process = m_kernel.ApplicationProcess();
  77. ASSERT(cur_process != nullptr);
  78. return cur_process;
  79. }
  80. } else if constexpr (std::derived_from<KThread, T>) {
  81. if (handle == Svc::PseudoHandle::CurrentThread) {
  82. auto* const cur_thread = GetCurrentThreadPointer(m_kernel);
  83. ASSERT(cur_thread != nullptr);
  84. return cur_thread;
  85. }
  86. }
  87. return this->template GetObjectWithoutPseudoHandle<T>(handle);
  88. }
  89. KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(Handle handle) const {
  90. // Lock and look up in table.
  91. KScopedDisableDispatch dd{m_kernel};
  92. KScopedSpinLock lk(m_lock);
  93. return this->GetObjectImpl(handle);
  94. }
  95. KScopedAutoObject<KAutoObject> GetObjectForIpc(Handle handle, KThread* cur_thread) const;
  96. KScopedAutoObject<KAutoObject> GetObjectByIndex(Handle* out_handle, size_t index) const {
  97. KScopedDisableDispatch dd{m_kernel};
  98. KScopedSpinLock lk(m_lock);
  99. return this->GetObjectByIndexImpl(out_handle, index);
  100. }
  101. Result Reserve(Handle* out_handle);
  102. void Unreserve(Handle handle);
  103. Result Add(Handle* out_handle, KAutoObject* obj);
  104. void Register(Handle handle, KAutoObject* obj);
  105. template <typename T>
  106. bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
  107. // Try to convert and open all the handles.
  108. size_t num_opened;
  109. {
  110. // Lock the table.
  111. KScopedDisableDispatch dd{m_kernel};
  112. KScopedSpinLock lk(m_lock);
  113. for (num_opened = 0; num_opened < num_handles; num_opened++) {
  114. // Get the current handle.
  115. const auto cur_handle = handles[num_opened];
  116. // Get the object for the current handle.
  117. KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
  118. if (cur_object == nullptr) [[unlikely]] {
  119. break;
  120. }
  121. // Cast the current object to the desired type.
  122. T* cur_t = cur_object->DynamicCast<T*>();
  123. if (cur_t == nullptr) [[unlikely]] {
  124. break;
  125. }
  126. // Open a reference to the current object.
  127. cur_t->Open();
  128. out[num_opened] = cur_t;
  129. }
  130. }
  131. // If we converted every object, succeed.
  132. if (num_opened == num_handles) [[likely]] {
  133. return true;
  134. }
  135. // If we didn't convert entry object, close the ones we opened.
  136. for (size_t i = 0; i < num_opened; i++) {
  137. out[i]->Close();
  138. }
  139. return false;
  140. }
  141. private:
  142. s32 AllocateEntry() {
  143. ASSERT(m_count < m_table_size);
  144. const auto index = m_free_head_index;
  145. m_free_head_index = m_entry_infos[index].GetNextFreeIndex();
  146. m_max_count = std::max(m_max_count, ++m_count);
  147. return index;
  148. }
  149. void FreeEntry(s32 index) {
  150. ASSERT(m_count > 0);
  151. m_objects[index] = nullptr;
  152. m_entry_infos[index].next_free_index = static_cast<s16>(m_free_head_index);
  153. m_free_head_index = index;
  154. --m_count;
  155. }
  156. u16 AllocateLinearId() {
  157. const u16 id = m_next_linear_id++;
  158. if (m_next_linear_id > MaxLinearId) {
  159. m_next_linear_id = MinLinearId;
  160. }
  161. return id;
  162. }
  163. bool IsValidHandle(Handle handle) const {
  164. // Unpack the handle.
  165. const auto handle_pack = HandlePack(handle);
  166. const auto raw_value = handle_pack.raw;
  167. const auto index = handle_pack.index;
  168. const auto linear_id = handle_pack.linear_id;
  169. const auto reserved = handle_pack.reserved;
  170. ASSERT(reserved == 0);
  171. // Validate our indexing information.
  172. if (raw_value == 0) [[unlikely]] {
  173. return false;
  174. }
  175. if (linear_id == 0) [[unlikely]] {
  176. return false;
  177. }
  178. if (index >= m_table_size) [[unlikely]] {
  179. return false;
  180. }
  181. // Check that there's an object, and our serial id is correct.
  182. if (m_objects[index] == nullptr) [[unlikely]] {
  183. return false;
  184. }
  185. if (m_entry_infos[index].GetLinearId() != linear_id) [[unlikely]] {
  186. return false;
  187. }
  188. return true;
  189. }
  190. KAutoObject* GetObjectImpl(Handle handle) const {
  191. // Handles must not have reserved bits set.
  192. const auto handle_pack = HandlePack(handle);
  193. if (handle_pack.reserved != 0) [[unlikely]] {
  194. return nullptr;
  195. }
  196. if (this->IsValidHandle(handle)) [[likely]] {
  197. return m_objects[handle_pack.index];
  198. } else {
  199. return nullptr;
  200. }
  201. }
  202. KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const {
  203. // Index must be in bounds.
  204. if (index >= m_table_size) [[unlikely]] {
  205. return nullptr;
  206. }
  207. // Ensure entry has an object.
  208. if (KAutoObject* obj = m_objects[index]; obj != nullptr) {
  209. *out_handle = EncodeHandle(static_cast<u16>(index), m_entry_infos[index].GetLinearId());
  210. return obj;
  211. } else {
  212. return nullptr;
  213. }
  214. }
  215. private:
  216. union HandlePack {
  217. constexpr HandlePack() = default;
  218. constexpr HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {}
  219. u32 raw{};
  220. BitField<0, 15, u32> index;
  221. BitField<15, 15, u32> linear_id;
  222. BitField<30, 2, u32> reserved;
  223. };
  224. static constexpr Handle EncodeHandle(u16 index, u16 linear_id) {
  225. HandlePack handle{};
  226. handle.index.Assign(index);
  227. handle.linear_id.Assign(linear_id);
  228. handle.reserved.Assign(0);
  229. return handle.raw;
  230. }
  231. private:
  232. static constexpr u16 MinLinearId = 1;
  233. static constexpr u16 MaxLinearId = 0x7FFF;
  234. union EntryInfo {
  235. u16 linear_id;
  236. s16 next_free_index;
  237. constexpr u16 GetLinearId() const {
  238. return linear_id;
  239. }
  240. constexpr s32 GetNextFreeIndex() const {
  241. return next_free_index;
  242. }
  243. };
  244. private:
  245. KernelCore& m_kernel;
  246. std::array<EntryInfo, MaxTableSize> m_entry_infos{};
  247. std::array<KAutoObject*, MaxTableSize> m_objects{};
  248. mutable KSpinLock m_lock;
  249. s32 m_free_head_index{};
  250. u16 m_table_size{};
  251. u16 m_max_count{};
  252. u16 m_next_linear_id{};
  253. u16 m_count{};
  254. };
  255. } // namespace Kernel