summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/kernel.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/kernel.h')
-rw-r--r--src/core/hle/kernel/kernel.h217
1 files changed, 127 insertions, 90 deletions
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 8d3937ce8..7f86fd07d 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -12,9 +12,17 @@
12typedef u32 Handle; 12typedef u32 Handle;
13typedef s32 Result; 13typedef s32 Result;
14 14
15const Handle INVALID_HANDLE = 0;
16
15namespace Kernel { 17namespace Kernel {
16 18
17enum KernelHandle { 19// TODO: Verify code
20const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
21 ErrorSummary::OutOfResource, ErrorLevel::Temporary);
22// TOOD: Verify code
23const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel);
24
25enum KernelHandle : Handle {
18 CurrentThread = 0xFFFF8000, 26 CurrentThread = 0xFFFF8000,
19 CurrentProcess = 0xFFFF8001, 27 CurrentProcess = 0xFFFF8001,
20}; 28};
@@ -22,7 +30,7 @@ enum KernelHandle {
22enum class HandleType : u32 { 30enum class HandleType : u32 {
23 Unknown = 0, 31 Unknown = 0,
24 Port = 1, 32 Port = 1,
25 Service = 2, 33 Session = 2,
26 Event = 3, 34 Event = 3,
27 Mutex = 4, 35 Mutex = 4,
28 SharedMemory = 5, 36 SharedMemory = 5,
@@ -30,20 +38,17 @@ enum class HandleType : u32 {
30 Thread = 7, 38 Thread = 7,
31 Process = 8, 39 Process = 8,
32 AddressArbiter = 9, 40 AddressArbiter = 9,
33 File = 10, 41 Semaphore = 10,
34 Semaphore = 11,
35 Archive = 12,
36 Directory = 13,
37}; 42};
38 43
39enum { 44enum {
40 DEFAULT_STACK_SIZE = 0x4000, 45 DEFAULT_STACK_SIZE = 0x4000,
41}; 46};
42 47
43class ObjectPool; 48class HandleTable;
44 49
45class Object : NonCopyable { 50class Object : NonCopyable {
46 friend class ObjectPool; 51 friend class HandleTable;
47 u32 handle; 52 u32 handle;
48public: 53public:
49 virtual ~Object() {} 54 virtual ~Object() {}
@@ -53,113 +58,145 @@ public:
53 virtual Kernel::HandleType GetHandleType() const = 0; 58 virtual Kernel::HandleType GetHandleType() const = 0;
54 59
55 /** 60 /**
56 * Synchronize kernel object. 61 * Wait for kernel object to synchronize.
57 * @return True if the current thread should wait as a result of the sync 62 * @return True if the current thread should wait as a result of the wait
58 */ 63 */
59 virtual ResultVal<bool> SyncRequest() { 64 virtual ResultVal<bool> WaitSynchronization() {
60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); 65 LOG_ERROR(Kernel, "(UNIMPLEMENTED)");
61 return UnimplementedFunction(ErrorModule::Kernel); 66 return UnimplementedFunction(ErrorModule::Kernel);
62 } 67 }
63 68
64 /** 69private:
65 * Wait for kernel object to synchronize. 70 friend void intrusive_ptr_add_ref(Object*);
66 * @return True if the current thread should wait as a result of the wait 71 friend void intrusive_ptr_release(Object*);
67 */ 72
68 virtual ResultVal<bool> WaitSynchronization() = 0; 73 unsigned int ref_count = 0;
69}; 74};
70 75
71class ObjectPool : NonCopyable { 76// Special functions that will later be used by boost::instrusive_ptr to do automatic ref-counting
72public: 77inline void intrusive_ptr_add_ref(Object* object) {
73 ObjectPool(); 78 ++object->ref_count;
74 ~ObjectPool() {} 79}
75 80
76 // Allocates a handle within the range and inserts the object into the map. 81inline void intrusive_ptr_release(Object* object) {
77 Handle Create(Object* obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); 82 if (--object->ref_count == 0) {
83 delete object;
84 }
85}
78 86
79 static Object* CreateByIDType(int type); 87/**
88 * This class allows the creation of Handles, which are references to objects that can be tested
89 * for validity and looked up. Here they are used to pass references to kernel objects to/from the
90 * emulated process. it has been designed so that it follows the same handle format and has
91 * approximately the same restrictions as the handle manager in the CTR-OS.
92 *
93 * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
94 * The slot index is used to index into the arrays in this class to access the data corresponding
95 * to the Handle.
96 *
97 * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
98 * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
99 * value of the counter is stored into the Handle as well as in the handle table (in the
100 * "generations" array). When looking up a handle, the Handle's generation must match with the
101 * value stored on the class, otherwise the Handle is considered invalid.
102 *
103 * To find free slots when allocating a Handle without needing to scan the entire object array, the
104 * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
105 * When a Handle is created, an index is popped off the list and used for the new Handle. When it
106 * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
107 * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
108 * verified and isn't likely to cause any problems.
109 */
110class HandleTable final : NonCopyable {
111public:
112 HandleTable();
80 113
81 template <class T> 114 /**
82 void Destroy(Handle handle) { 115 * Allocates a handle for the given object.
83 if (Get<T>(handle)) { 116 * @return The created Handle or one of the following errors:
84 occupied[handle - HANDLE_OFFSET] = false; 117 * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
85 delete pool[handle - HANDLE_OFFSET]; 118 */
86 } 119 ResultVal<Handle> Create(Object* obj);
87 }
88 120
89 bool IsValid(Handle handle); 121 /**
122 * Returns a new handle that points to the same object as the passed in handle.
123 * @return The duplicated Handle or one of the following errors:
124 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
125 * - Any errors returned by `Create()`.
126 */
127 ResultVal<Handle> Duplicate(Handle handle);
90 128
91 template <class T> 129 /**
92 T* Get(Handle handle) { 130 * Closes a handle, removing it from the table and decreasing the object's ref-count.
93 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { 131 * @return `RESULT_SUCCESS` or one of the following errors:
94 if (handle != 0) { 132 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
95 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 133 */
96 } 134 ResultCode Close(Handle handle);
97 return nullptr;
98 } else {
99 Object* t = pool[handle - HANDLE_OFFSET];
100 if (t->GetHandleType() != T::GetStaticHandleType()) {
101 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
102 return nullptr;
103 }
104 return static_cast<T*>(t);
105 }
106 }
107 135
108 // ONLY use this when you know the handle is valid. 136 /// Checks if a handle is valid and points to an existing object.
109 template <class T> 137 bool IsValid(Handle handle) const;
110 T *GetFast(Handle handle) {
111 const Handle realHandle = handle - HANDLE_OFFSET;
112 _dbg_assert_(KERNEL, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]);
113 return static_cast<T*>(pool[realHandle]);
114 }
115 138
116 template <class T, typename ArgT> 139 /**
117 void Iterate(bool func(T*, ArgT), ArgT arg) { 140 * Looks up a handle.
118 int type = T::GetStaticIDType(); 141 * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid.
119 for (int i = 0; i < MAX_COUNT; i++) 142 */
120 { 143 Object* GetGeneric(Handle handle) const;
121 if (!occupied[i])
122 continue;
123 T* t = static_cast<T*>(pool[i]);
124 if (t->GetIDType() == type) {
125 if (!func(t, arg))
126 break;
127 }
128 }
129 }
130 144
131 bool GetIDType(Handle handle, HandleType* type) const { 145 /**
132 if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || 146 * Looks up a handle while verifying its type.
133 !occupied[handle - HANDLE_OFFSET]) { 147 * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
134 ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 148 * type differs from the handle type `T::HANDLE_TYPE`.
135 return false; 149 */
150 template <class T>
151 T* Get(Handle handle) const {
152 Object* object = GetGeneric(handle);
153 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
154 return static_cast<T*>(object);
136 } 155 }
137 Object* t = pool[handle - HANDLE_OFFSET]; 156 return nullptr;
138 *type = t->GetHandleType();
139 return true;
140 } 157 }
141 158
142 Object* &operator [](Handle handle); 159 /// Closes all handles held in this table.
143 void List();
144 void Clear(); 160 void Clear();
145 int GetCount();
146 161
147private: 162private:
163 /**
164 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
165 * reduced by ExHeader values, but this is not emulated here.
166 */
167 static const size_t MAX_COUNT = 4096;
148 168
149 enum { 169 static size_t GetSlot(Handle handle) { return handle >> 15; }
150 MAX_COUNT = 0x1000, 170 static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; }
151 HANDLE_OFFSET = 0x100,
152 INITIAL_NEXT_ID = 0x10,
153 };
154 171
155 std::array<Object*, MAX_COUNT> pool; 172 /// Stores the Object referenced by the handle or null if the slot is empty.
156 std::array<bool, MAX_COUNT> occupied; 173 std::array<Object*, MAX_COUNT> objects;
157 int next_id; 174
175 /**
176 * The value of `next_generation` when the handle was created, used to check for validity. For
177 * empty slots, contains the index of the next free slot in the list.
178 */
179 std::array<u16, MAX_COUNT> generations;
180
181 /**
182 * Global counter of the number of created handles. Stored in `generations` when a handle is
183 * created, and wraps around to 1 when it hits 0x8000.
184 */
185 u16 next_generation;
186
187 /// Head of the free slots linked list.
188 u16 next_free_slot;
158}; 189};
159 190
160extern ObjectPool g_object_pool; 191extern HandleTable g_handle_table;
161extern Handle g_main_thread; 192extern Handle g_main_thread;
162 193
194/// The ID code of the currently running game
195/// TODO(Subv): This variable should not be here,
196/// we need a way to store information about the currently loaded application
197/// for later query during runtime, maybe using the LDR service?
198extern u64 g_program_id;
199
163/// Initialize the kernel 200/// Initialize the kernel
164void Init(); 201void Init();
165 202