kernel.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright 2014 Citra Emulator Project / PPSSPP Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <algorithm>
  6. #include <array>
  7. #include <cstddef>
  8. #include <string>
  9. #include <vector>
  10. #include <boost/smart_ptr/intrusive_ptr.hpp>
  11. #include "common/common_types.h"
  12. #include "core/hle/hle.h"
  13. #include "core/hle/result.h"
  14. namespace Kernel {
  15. class Thread;
  16. // TODO: Verify code
  17. const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
  18. ErrorSummary::OutOfResource, ErrorLevel::Temporary);
  19. // TOOD: Verify code
  20. const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel,
  21. ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
  22. enum KernelHandle : Handle {
  23. CurrentThread = 0xFFFF8000,
  24. CurrentProcess = 0xFFFF8001,
  25. };
  26. enum class HandleType : u32 {
  27. Unknown = 0,
  28. Session = 2,
  29. Event = 3,
  30. Mutex = 4,
  31. SharedMemory = 5,
  32. Redirection = 6,
  33. Thread = 7,
  34. Process = 8,
  35. AddressArbiter = 9,
  36. Semaphore = 10,
  37. Timer = 11,
  38. ResourceLimit = 12,
  39. CodeSet = 13,
  40. ClientPort = 14,
  41. ServerPort = 15,
  42. };
  43. enum {
  44. DEFAULT_STACK_SIZE = 0x4000,
  45. };
  46. enum class ResetType {
  47. OneShot,
  48. Sticky,
  49. Pulse,
  50. };
  51. class Object : NonCopyable {
  52. public:
  53. virtual ~Object() {}
  54. /// Returns a unique identifier for the object. For debugging purposes only.
  55. unsigned int GetObjectId() const {
  56. return object_id;
  57. }
  58. virtual std::string GetTypeName() const {
  59. return "[BAD KERNEL OBJECT TYPE]";
  60. }
  61. virtual std::string GetName() const {
  62. return "[UNKNOWN KERNEL OBJECT]";
  63. }
  64. virtual Kernel::HandleType GetHandleType() const = 0;
  65. /**
  66. * Check if a thread can wait on the object
  67. * @return True if a thread can wait on the object, otherwise false
  68. */
  69. bool IsWaitable() const {
  70. switch (GetHandleType()) {
  71. case HandleType::Session:
  72. case HandleType::ServerPort:
  73. case HandleType::Event:
  74. case HandleType::Mutex:
  75. case HandleType::Thread:
  76. case HandleType::Semaphore:
  77. case HandleType::Timer:
  78. return true;
  79. case HandleType::Unknown:
  80. case HandleType::SharedMemory:
  81. case HandleType::Redirection:
  82. case HandleType::Process:
  83. case HandleType::AddressArbiter:
  84. case HandleType::ResourceLimit:
  85. case HandleType::CodeSet:
  86. case HandleType::ClientPort:
  87. return false;
  88. }
  89. }
  90. public:
  91. static unsigned int next_object_id;
  92. private:
  93. friend void intrusive_ptr_add_ref(Object*);
  94. friend void intrusive_ptr_release(Object*);
  95. unsigned int ref_count = 0;
  96. unsigned int object_id = next_object_id++;
  97. };
  98. // Special functions used by boost::instrusive_ptr to do automatic ref-counting
  99. inline void intrusive_ptr_add_ref(Object* object) {
  100. ++object->ref_count;
  101. }
  102. inline void intrusive_ptr_release(Object* object) {
  103. if (--object->ref_count == 0) {
  104. delete object;
  105. }
  106. }
  107. template <typename T>
  108. using SharedPtr = boost::intrusive_ptr<T>;
  109. /// Class that represents a Kernel object that a thread can be waiting on
  110. class WaitObject : public Object {
  111. public:
  112. /**
  113. * Check if the current thread should wait until the object is available
  114. * @return True if the current thread should wait due to this object being unavailable
  115. */
  116. virtual bool ShouldWait() = 0;
  117. /// Acquire/lock the object if it is available
  118. virtual void Acquire() = 0;
  119. /**
  120. * Add a thread to wait on this object
  121. * @param thread Pointer to thread to add
  122. */
  123. void AddWaitingThread(SharedPtr<Thread> thread);
  124. /**
  125. * Removes a thread from waiting on this object (e.g. if it was resumed already)
  126. * @param thread Pointer to thread to remove
  127. */
  128. void RemoveWaitingThread(Thread* thread);
  129. /// Wake up all threads waiting on this object
  130. void WakeupAllWaitingThreads();
  131. /// Obtains the highest priority thread that is ready to run from this object's waiting list.
  132. SharedPtr<Thread> GetHighestPriorityReadyThread();
  133. /// Get a const reference to the waiting threads list for debug use
  134. const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
  135. private:
  136. /// Threads waiting for this object to become available
  137. std::vector<SharedPtr<Thread>> waiting_threads;
  138. };
  139. /**
  140. * This class allows the creation of Handles, which are references to objects that can be tested
  141. * for validity and looked up. Here they are used to pass references to kernel objects to/from the
  142. * emulated process. it has been designed so that it follows the same handle format and has
  143. * approximately the same restrictions as the handle manager in the CTR-OS.
  144. *
  145. * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
  146. * The slot index is used to index into the arrays in this class to access the data corresponding
  147. * to the Handle.
  148. *
  149. * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
  150. * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
  151. * value of the counter is stored into the Handle as well as in the handle table (in the
  152. * "generations" array). When looking up a handle, the Handle's generation must match with the
  153. * value stored on the class, otherwise the Handle is considered invalid.
  154. *
  155. * To find free slots when allocating a Handle without needing to scan the entire object array, the
  156. * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
  157. * When a Handle is created, an index is popped off the list and used for the new Handle. When it
  158. * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
  159. * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
  160. * verified and isn't likely to cause any problems.
  161. */
  162. class HandleTable final : NonCopyable {
  163. public:
  164. HandleTable();
  165. /**
  166. * Allocates a handle for the given object.
  167. * @return The created Handle or one of the following errors:
  168. * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
  169. */
  170. ResultVal<Handle> Create(SharedPtr<Object> obj);
  171. /**
  172. * Returns a new handle that points to the same object as the passed in handle.
  173. * @return The duplicated Handle or one of the following errors:
  174. * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
  175. * - Any errors returned by `Create()`.
  176. */
  177. ResultVal<Handle> Duplicate(Handle handle);
  178. /**
  179. * Closes a handle, removing it from the table and decreasing the object's ref-count.
  180. * @return `RESULT_SUCCESS` or one of the following errors:
  181. * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
  182. */
  183. ResultCode Close(Handle handle);
  184. /// Checks if a handle is valid and points to an existing object.
  185. bool IsValid(Handle handle) const;
  186. /**
  187. * Looks up a handle.
  188. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
  189. */
  190. SharedPtr<Object> GetGeneric(Handle handle) const;
  191. /**
  192. * Looks up a handle while verifying its type.
  193. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
  194. * type differs from the handle type `T::HANDLE_TYPE`.
  195. */
  196. template <class T>
  197. SharedPtr<T> Get(Handle handle) const {
  198. SharedPtr<Object> object = GetGeneric(handle);
  199. if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
  200. return boost::static_pointer_cast<T>(std::move(object));
  201. }
  202. return nullptr;
  203. }
  204. /**
  205. * Looks up a handle while verifying that it is an object that a thread can wait on
  206. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or it is
  207. * not a waitable object.
  208. */
  209. SharedPtr<WaitObject> GetWaitObject(Handle handle) const {
  210. SharedPtr<Object> object = GetGeneric(handle);
  211. if (object != nullptr && object->IsWaitable()) {
  212. return boost::static_pointer_cast<WaitObject>(std::move(object));
  213. }
  214. return nullptr;
  215. }
  216. /// Closes all handles held in this table.
  217. void Clear();
  218. private:
  219. /**
  220. * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
  221. * reduced by ExHeader values, but this is not emulated here.
  222. */
  223. static const size_t MAX_COUNT = 4096;
  224. static u16 GetSlot(Handle handle) {
  225. return handle >> 15;
  226. }
  227. static u16 GetGeneration(Handle handle) {
  228. return handle & 0x7FFF;
  229. }
  230. /// Stores the Object referenced by the handle or null if the slot is empty.
  231. std::array<SharedPtr<Object>, MAX_COUNT> objects;
  232. /**
  233. * The value of `next_generation` when the handle was created, used to check for validity. For
  234. * empty slots, contains the index of the next free slot in the list.
  235. */
  236. std::array<u16, MAX_COUNT> generations;
  237. /**
  238. * Global counter of the number of created handles. Stored in `generations` when a handle is
  239. * created, and wraps around to 1 when it hits 0x8000.
  240. */
  241. u16 next_generation;
  242. /// Head of the free slots linked list.
  243. u16 next_free_slot;
  244. };
  245. extern HandleTable g_handle_table;
  246. /// Initialize the kernel with the specified system mode.
  247. void Init(u32 system_mode);
  248. /// Shutdown the kernel
  249. void Shutdown();
  250. } // namespace