|
|
@ -21,33 +21,38 @@ namespace Kernel { |
|
|
class KernelCore; |
|
|
class KernelCore; |
|
|
|
|
|
|
|
|
class KHandleTable { |
|
|
class KHandleTable { |
|
|
public: |
|
|
|
|
|
YUZU_NON_COPYABLE(KHandleTable); |
|
|
YUZU_NON_COPYABLE(KHandleTable); |
|
|
YUZU_NON_MOVEABLE(KHandleTable); |
|
|
YUZU_NON_MOVEABLE(KHandleTable); |
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
static constexpr size_t MaxTableSize = 1024; |
|
|
static constexpr size_t MaxTableSize = 1024; |
|
|
|
|
|
|
|
|
explicit KHandleTable(KernelCore& kernel_); |
|
|
|
|
|
~KHandleTable(); |
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {} |
|
|
|
|
|
|
|
|
Result Initialize(s32 size) { |
|
|
Result Initialize(s32 size) { |
|
|
|
|
|
// Check that the table size is valid. |
|
|
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); |
|
|
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); |
|
|
|
|
|
|
|
|
|
|
|
// Lock. |
|
|
|
|
|
KScopedDisableDispatch dd{m_kernel}; |
|
|
|
|
|
KScopedSpinLock lk(m_lock); |
|
|
|
|
|
|
|
|
// Initialize all fields. |
|
|
// Initialize all fields. |
|
|
m_max_count = 0; |
|
|
m_max_count = 0; |
|
|
m_table_size = static_cast<u16>((size <= 0) ? MaxTableSize : size); |
|
|
|
|
|
|
|
|
m_table_size = static_cast<s16>((size <= 0) ? MaxTableSize : size); |
|
|
m_next_linear_id = MinLinearId; |
|
|
m_next_linear_id = MinLinearId; |
|
|
m_count = 0; |
|
|
m_count = 0; |
|
|
m_free_head_index = -1; |
|
|
m_free_head_index = -1; |
|
|
|
|
|
|
|
|
// Free all entries. |
|
|
// Free all entries. |
|
|
for (s16 i = 0; i < static_cast<s16>(m_table_size); ++i) { |
|
|
|
|
|
|
|
|
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) { |
|
|
m_objects[i] = nullptr; |
|
|
m_objects[i] = nullptr; |
|
|
m_entry_infos[i].next_free_index = i - 1; |
|
|
|
|
|
|
|
|
m_entry_infos[i].next_free_index = static_cast<s16>(i - 1); |
|
|
m_free_head_index = i; |
|
|
m_free_head_index = i; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return ResultSuccess; |
|
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
size_t GetTableSize() const { |
|
|
size_t GetTableSize() const { |
|
|
@ -66,13 +71,13 @@ public: |
|
|
template <typename T = KAutoObject> |
|
|
template <typename T = KAutoObject> |
|
|
KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { |
|
|
KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { |
|
|
// Lock and look up in table. |
|
|
// Lock and look up in table. |
|
|
KScopedDisableDispatch dd(kernel); |
|
|
|
|
|
|
|
|
KScopedDisableDispatch dd{m_kernel}; |
|
|
KScopedSpinLock lk(m_lock); |
|
|
KScopedSpinLock lk(m_lock); |
|
|
|
|
|
|
|
|
if constexpr (std::is_same_v<T, KAutoObject>) { |
|
|
|
|
|
|
|
|
if constexpr (std::is_same<T, KAutoObject>::value) { |
|
|
return this->GetObjectImpl(handle); |
|
|
return this->GetObjectImpl(handle); |
|
|
} else { |
|
|
} else { |
|
|
if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) { |
|
|
|
|
|
|
|
|
if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) [[likely]] { |
|
|
return obj->DynamicCast<T*>(); |
|
|
return obj->DynamicCast<T*>(); |
|
|
} else { |
|
|
} else { |
|
|
return nullptr; |
|
|
return nullptr; |
|
|
@ -85,13 +90,13 @@ public: |
|
|
// Handle pseudo-handles. |
|
|
// Handle pseudo-handles. |
|
|
if constexpr (std::derived_from<KProcess, T>) { |
|
|
if constexpr (std::derived_from<KProcess, T>) { |
|
|
if (handle == Svc::PseudoHandle::CurrentProcess) { |
|
|
if (handle == Svc::PseudoHandle::CurrentProcess) { |
|
|
auto* const cur_process = kernel.CurrentProcess(); |
|
|
|
|
|
|
|
|
auto* const cur_process = m_kernel.CurrentProcess(); |
|
|
ASSERT(cur_process != nullptr); |
|
|
ASSERT(cur_process != nullptr); |
|
|
return cur_process; |
|
|
return cur_process; |
|
|
} |
|
|
} |
|
|
} else if constexpr (std::derived_from<KThread, T>) { |
|
|
} else if constexpr (std::derived_from<KThread, T>) { |
|
|
if (handle == Svc::PseudoHandle::CurrentThread) { |
|
|
if (handle == Svc::PseudoHandle::CurrentThread) { |
|
|
auto* const cur_thread = GetCurrentThreadPointer(kernel); |
|
|
|
|
|
|
|
|
auto* const cur_thread = GetCurrentThreadPointer(m_kernel); |
|
|
ASSERT(cur_thread != nullptr); |
|
|
ASSERT(cur_thread != nullptr); |
|
|
return cur_thread; |
|
|
return cur_thread; |
|
|
} |
|
|
} |
|
|
@ -100,6 +105,37 @@ public: |
|
|
return this->template GetObjectWithoutPseudoHandle<T>(handle); |
|
|
return this->template GetObjectWithoutPseudoHandle<T>(handle); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(Handle handle) const { |
|
|
|
|
|
// Lock and look up in table. |
|
|
|
|
|
KScopedDisableDispatch dd{m_kernel}; |
|
|
|
|
|
KScopedSpinLock lk(m_lock); |
|
|
|
|
|
|
|
|
|
|
|
return this->GetObjectImpl(handle); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
KScopedAutoObject<KAutoObject> GetObjectForIpc(Handle handle, KThread* cur_thread) const { |
|
|
|
|
|
// Handle pseudo-handles. |
|
|
|
|
|
ASSERT(cur_thread != nullptr); |
|
|
|
|
|
if (handle == Svc::PseudoHandle::CurrentProcess) { |
|
|
|
|
|
auto* const cur_process = |
|
|
|
|
|
static_cast<KAutoObject*>(static_cast<void*>(cur_thread->GetOwnerProcess())); |
|
|
|
|
|
ASSERT(cur_process != nullptr); |
|
|
|
|
|
return cur_process; |
|
|
|
|
|
} |
|
|
|
|
|
if (handle == Svc::PseudoHandle::CurrentThread) { |
|
|
|
|
|
return static_cast<KAutoObject*>(cur_thread); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return GetObjectForIpcWithoutPseudoHandle(handle); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
KScopedAutoObject<KAutoObject> GetObjectByIndex(Handle* out_handle, size_t index) const { |
|
|
|
|
|
KScopedDisableDispatch dd{m_kernel}; |
|
|
|
|
|
KScopedSpinLock lk(m_lock); |
|
|
|
|
|
|
|
|
|
|
|
return this->GetObjectByIndexImpl(out_handle, index); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
Result Reserve(Handle* out_handle); |
|
|
Result Reserve(Handle* out_handle); |
|
|
void Unreserve(Handle handle); |
|
|
void Unreserve(Handle handle); |
|
|
|
|
|
|
|
|
@ -112,7 +148,7 @@ public: |
|
|
size_t num_opened; |
|
|
size_t num_opened; |
|
|
{ |
|
|
{ |
|
|
// Lock the table. |
|
|
// Lock the table. |
|
|
KScopedDisableDispatch dd(kernel); |
|
|
|
|
|
|
|
|
KScopedDisableDispatch dd{m_kernel}; |
|
|
KScopedSpinLock lk(m_lock); |
|
|
KScopedSpinLock lk(m_lock); |
|
|
for (num_opened = 0; num_opened < num_handles; num_opened++) { |
|
|
for (num_opened = 0; num_opened < num_handles; num_opened++) { |
|
|
// Get the current handle. |
|
|
// Get the current handle. |
|
|
@ -120,13 +156,13 @@ public: |
|
|
|
|
|
|
|
|
// Get the object for the current handle. |
|
|
// Get the object for the current handle. |
|
|
KAutoObject* cur_object = this->GetObjectImpl(cur_handle); |
|
|
KAutoObject* cur_object = this->GetObjectImpl(cur_handle); |
|
|
if (cur_object == nullptr) { |
|
|
|
|
|
|
|
|
if (cur_object == nullptr) [[unlikely]] { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Cast the current object to the desired type. |
|
|
// Cast the current object to the desired type. |
|
|
T* cur_t = cur_object->DynamicCast<T*>(); |
|
|
T* cur_t = cur_object->DynamicCast<T*>(); |
|
|
if (cur_t == nullptr) { |
|
|
|
|
|
|
|
|
if (cur_t == nullptr) [[unlikely]] { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -137,7 +173,7 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// If we converted every object, succeed. |
|
|
// If we converted every object, succeed. |
|
|
if (num_opened == num_handles) { |
|
|
|
|
|
|
|
|
if (num_opened == num_handles) [[likely]] { |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -191,21 +227,21 @@ private: |
|
|
ASSERT(reserved == 0); |
|
|
ASSERT(reserved == 0); |
|
|
|
|
|
|
|
|
// Validate our indexing information. |
|
|
// Validate our indexing information. |
|
|
if (raw_value == 0) { |
|
|
|
|
|
|
|
|
if (raw_value == 0) [[unlikely]] { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
if (linear_id == 0) { |
|
|
|
|
|
|
|
|
if (linear_id == 0) [[unlikely]] { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
if (index >= m_table_size) { |
|
|
|
|
|
|
|
|
if (index >= m_table_size) [[unlikely]] { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check that there's an object, and our serial id is correct. |
|
|
// Check that there's an object, and our serial id is correct. |
|
|
if (m_objects[index] == nullptr) { |
|
|
|
|
|
|
|
|
if (m_objects[index] == nullptr) [[unlikely]] { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
if (m_entry_infos[index].GetLinearId() != linear_id) { |
|
|
|
|
|
|
|
|
if (m_entry_infos[index].GetLinearId() != linear_id) [[unlikely]] { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -215,11 +251,11 @@ private: |
|
|
KAutoObject* GetObjectImpl(Handle handle) const { |
|
|
KAutoObject* GetObjectImpl(Handle handle) const { |
|
|
// Handles must not have reserved bits set. |
|
|
// Handles must not have reserved bits set. |
|
|
const auto handle_pack = HandlePack(handle); |
|
|
const auto handle_pack = HandlePack(handle); |
|
|
if (handle_pack.reserved != 0) { |
|
|
|
|
|
|
|
|
if (handle_pack.reserved != 0) [[unlikely]] { |
|
|
return nullptr; |
|
|
return nullptr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (this->IsValidHandle(handle)) { |
|
|
|
|
|
|
|
|
if (this->IsValidHandle(handle)) [[likely]] { |
|
|
return m_objects[handle_pack.index]; |
|
|
return m_objects[handle_pack.index]; |
|
|
} else { |
|
|
} else { |
|
|
return nullptr; |
|
|
return nullptr; |
|
|
@ -227,9 +263,8 @@ private: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const { |
|
|
KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const { |
|
|
|
|
|
|
|
|
// Index must be in bounds. |
|
|
// Index must be in bounds. |
|
|
if (index >= m_table_size) { |
|
|
|
|
|
|
|
|
if (index >= m_table_size) [[unlikely]] { |
|
|
return nullptr; |
|
|
return nullptr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -244,18 +279,15 @@ private: |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
union HandlePack { |
|
|
union HandlePack { |
|
|
HandlePack() = default; |
|
|
|
|
|
HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {} |
|
|
|
|
|
|
|
|
constexpr HandlePack() = default; |
|
|
|
|
|
constexpr HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {} |
|
|
|
|
|
|
|
|
u32 raw; |
|
|
|
|
|
|
|
|
u32 raw{}; |
|
|
BitField<0, 15, u32> index; |
|
|
BitField<0, 15, u32> index; |
|
|
BitField<15, 15, u32> linear_id; |
|
|
BitField<15, 15, u32> linear_id; |
|
|
BitField<30, 2, u32> reserved; |
|
|
BitField<30, 2, u32> reserved; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
static constexpr u16 MinLinearId = 1; |
|
|
|
|
|
static constexpr u16 MaxLinearId = 0x7FFF; |
|
|
|
|
|
|
|
|
|
|
|
static constexpr Handle EncodeHandle(u16 index, u16 linear_id) { |
|
|
static constexpr Handle EncodeHandle(u16 index, u16 linear_id) { |
|
|
HandlePack handle{}; |
|
|
HandlePack handle{}; |
|
|
handle.index.Assign(index); |
|
|
handle.index.Assign(index); |
|
|
@ -264,6 +296,10 @@ private: |
|
|
return handle.raw; |
|
|
return handle.raw; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
static constexpr u16 MinLinearId = 1; |
|
|
|
|
|
static constexpr u16 MaxLinearId = 0x7FFF; |
|
|
|
|
|
|
|
|
union EntryInfo { |
|
|
union EntryInfo { |
|
|
u16 linear_id; |
|
|
u16 linear_id; |
|
|
s16 next_free_index; |
|
|
s16 next_free_index; |
|
|
@ -271,21 +307,21 @@ private: |
|
|
constexpr u16 GetLinearId() const { |
|
|
constexpr u16 GetLinearId() const { |
|
|
return linear_id; |
|
|
return linear_id; |
|
|
} |
|
|
} |
|
|
constexpr s16 GetNextFreeIndex() const { |
|
|
|
|
|
|
|
|
constexpr s32 GetNextFreeIndex() const { |
|
|
return next_free_index; |
|
|
return next_free_index; |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
|
|
|
KernelCore& m_kernel; |
|
|
std::array<EntryInfo, MaxTableSize> m_entry_infos{}; |
|
|
std::array<EntryInfo, MaxTableSize> m_entry_infos{}; |
|
|
std::array<KAutoObject*, MaxTableSize> m_objects{}; |
|
|
std::array<KAutoObject*, MaxTableSize> m_objects{}; |
|
|
s32 m_free_head_index{-1}; |
|
|
|
|
|
|
|
|
mutable KSpinLock m_lock; |
|
|
|
|
|
s32 m_free_head_index{}; |
|
|
u16 m_table_size{}; |
|
|
u16 m_table_size{}; |
|
|
u16 m_max_count{}; |
|
|
u16 m_max_count{}; |
|
|
u16 m_next_linear_id{MinLinearId}; |
|
|
|
|
|
|
|
|
u16 m_next_linear_id{}; |
|
|
u16 m_count{}; |
|
|
u16 m_count{}; |
|
|
mutable KSpinLock m_lock; |
|
|
|
|
|
KernelCore& kernel; |
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
} // namespace Kernel |
|
|
} // namespace Kernel |