| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | // Copyright 2014 Citra Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <array>
 | 
					
						
							|  |  |  | #include <cstddef>
 | 
					
						
							| 
									
										
										
										
											2019-12-07 22:09:20 -05:00
										 |  |  | #include <memory>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | #include "common/common_types.h"
 | 
					
						
							| 
									
										
										
										
											2021-04-03 19:11:46 -07:00
										 |  |  | #include "core/hle/kernel/k_auto_object.h"
 | 
					
						
							|  |  |  | #include "core/hle/kernel/kernel.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-01 22:40:00 -04:00
										 |  |  | #include "core/hle/kernel/object.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | #include "core/hle/result.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Kernel { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 13:18:03 -04:00
										 |  |  | class KernelCore; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | enum KernelHandle : Handle { | 
					
						
							| 
									
										
										
										
											2018-12-04 00:29:15 -05:00
										 |  |  |     InvalidHandle = 0, | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  |     CurrentThread = 0xFFFF8000, | 
					
						
							|  |  |  |     CurrentProcess = 0xFFFF8001, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This class allows the creation of Handles, which are references to objects that can be tested | 
					
						
							|  |  |  |  * for validity and looked up. Here they are used to pass references to kernel objects to/from the | 
					
						
							|  |  |  |  * emulated process. it has been designed so that it follows the same handle format and has | 
					
						
							|  |  |  |  * approximately the same restrictions as the handle manager in the CTR-OS. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0). | 
					
						
							|  |  |  |  * The slot index is used to index into the arrays in this class to access the data corresponding | 
					
						
							|  |  |  |  * to the Handle. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter | 
					
						
							|  |  |  |  * is kept and incremented every time a Handle is created. This is the Handle's "generation". The | 
					
						
							|  |  |  |  * value of the counter is stored into the Handle as well as in the handle table (in the | 
					
						
							|  |  |  |  * "generations" array). When looking up a handle, the Handle's generation must match with the | 
					
						
							|  |  |  |  * value stored on the class, otherwise the Handle is considered invalid. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * To find free slots when allocating a Handle without needing to scan the entire object array, the | 
					
						
							|  |  |  |  * generations field of unallocated slots is re-purposed as a linked list of indices to free slots. | 
					
						
							|  |  |  |  * When a Handle is created, an index is popped off the list and used for the new Handle. When it | 
					
						
							|  |  |  |  * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is | 
					
						
							|  |  |  |  * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been | 
					
						
							|  |  |  |  * verified and isn't likely to cause any problems. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class HandleTable final : NonCopyable { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2018-12-19 12:57:47 -05:00
										 |  |  |     /// This is the maximum limit of handles allowed per process in Horizon
 | 
					
						
							|  |  |  |     static constexpr std::size_t MAX_COUNT = 1024; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 13:18:03 -04:00
										 |  |  |     explicit HandleTable(KernelCore& kernel); | 
					
						
							| 
									
										
										
										
											2018-11-21 18:22:24 -05:00
										 |  |  |     ~HandleTable(); | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-25 10:13:52 -05:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * Sets the number of handles that may be in use at one time | 
					
						
							|  |  |  |      * for this handle table. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param handle_table_size The desired size to limit the handle table to. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @returns an error code indicating if initialization was successful. | 
					
						
							|  |  |  |      *          If initialization was not successful, then ERR_OUT_OF_MEMORY | 
					
						
							|  |  |  |      *          will be returned. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @pre handle_table_size must be within the range [0, 1024] | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     ResultCode SetSize(s32 handle_table_size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * Allocates a handle for the given object. | 
					
						
							|  |  |  |      * @return The created Handle or one of the following errors: | 
					
						
							| 
									
										
										
										
											2018-08-25 05:44:51 -04:00
										 |  |  |      *           - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-11-24 20:15:51 -05:00
										 |  |  |     ResultVal<Handle> Create(std::shared_ptr<Object> obj); | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Returns a new handle that points to the same object as the passed in handle. | 
					
						
							|  |  |  |      * @return The duplicated Handle or one of the following errors: | 
					
						
							|  |  |  |      *           - `ERR_INVALID_HANDLE`: an invalid handle was passed in. | 
					
						
							|  |  |  |      *           - Any errors returned by `Create()`. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     ResultVal<Handle> Duplicate(Handle handle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Closes a handle, removing it from the table and decreasing the object's ref-count. | 
					
						
							|  |  |  |      * @return `RESULT_SUCCESS` or one of the following errors: | 
					
						
							|  |  |  |      *           - `ERR_INVALID_HANDLE`: an invalid handle was passed in. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-04-03 19:11:46 -07:00
										 |  |  |     bool Remove(Handle handle); | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Checks if a handle is valid and points to an existing object.
 | 
					
						
							|  |  |  |     bool IsValid(Handle handle) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Looks up a handle. | 
					
						
							|  |  |  |      * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-04-03 22:22:36 -07:00
										 |  |  |     Object* GetGeneric(Handle handle) const; | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Looks up a handle while verifying its type. | 
					
						
							|  |  |  |      * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its | 
					
						
							|  |  |  |      *         type differs from the requested one. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     template <class T> | 
					
						
							| 
									
										
										
										
											2021-04-03 22:22:36 -07:00
										 |  |  |     T* Get(Handle handle) const { | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  |         return DynamicObjectCast<T>(GetGeneric(handle)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-03 19:11:46 -07:00
										 |  |  |     template <typename T = KAutoObject> | 
					
						
							|  |  |  |     KScopedAutoObject<T> GetObject(Handle handle) const { | 
					
						
							|  |  |  |         if (handle == CurrentThread) { | 
					
						
							|  |  |  |             return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast<T*>(); | 
					
						
							|  |  |  |         } else if (handle == CurrentProcess) { | 
					
						
							|  |  |  |             return kernel.CurrentProcess()->DynamicCast<T*>(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!IsValid(handle)) { | 
					
						
							|  |  |  |             return nullptr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto* obj = objects_new[static_cast<u16>(handle >> 15)]; | 
					
						
							|  |  |  |         return obj->DynamicCast<T*>(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T = KAutoObject> | 
					
						
							|  |  |  |     KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { | 
					
						
							|  |  |  |         if (!IsValid(handle)) { | 
					
						
							|  |  |  |             return nullptr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         auto* obj = objects_new[static_cast<u16>(handle >> 15)]; | 
					
						
							|  |  |  |         return obj->DynamicCast<T*>(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  |     /// Closes all handles held in this table.
 | 
					
						
							|  |  |  |     void Clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-03 19:11:46 -07:00
										 |  |  |     // NEW IMPL
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     ResultCode Add(Handle* out_handle, T* obj) { | 
					
						
							|  |  |  |         static_assert(std::is_base_of<KAutoObject, T>::value); | 
					
						
							|  |  |  |         return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | private: | 
					
						
							|  |  |  |     /// Stores the Object referenced by the handle or null if the slot is empty.
 | 
					
						
							| 
									
										
										
										
											2019-11-24 20:15:51 -05:00
										 |  |  |     std::array<std::shared_ptr<Object>, MAX_COUNT> objects; | 
					
						
							| 
									
										
										
										
											2021-04-03 19:11:46 -07:00
										 |  |  |     std::array<KAutoObject*, MAX_COUNT> objects_new{}; | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * The value of `next_generation` when the handle was created, used to check for validity. For | 
					
						
							|  |  |  |      * empty slots, contains the index of the next free slot in the list. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     std::array<u16, MAX_COUNT> generations; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-25 10:13:52 -05:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * The limited size of the handle table. This can be specified by process | 
					
						
							|  |  |  |      * capabilities in order to restrict the overall number of handles that | 
					
						
							|  |  |  |      * can be created in a process instance | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     u16 table_size = static_cast<u16>(MAX_COUNT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * Global counter of the number of created handles. Stored in `generations` when a handle is | 
					
						
							|  |  |  |      * created, and wraps around to 1 when it hits 0x8000. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-02-25 10:01:22 -05:00
										 |  |  |     u16 next_generation = 1; | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Head of the free slots linked list.
 | 
					
						
							| 
									
										
										
										
											2019-02-25 10:01:22 -05:00
										 |  |  |     u16 next_free_slot = 0; | 
					
						
							| 
									
										
										
										
											2020-07-15 13:18:03 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Underlying kernel instance that this handle table operates under.
 | 
					
						
							|  |  |  |     KernelCore& kernel; | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:48:02 -07:00
										 |  |  | } // namespace Kernel
 |