kernel.h 9.1 KB

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