mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-11-14 08:54:57 +00:00
hle: kernel: Migrate to KHandleTable.
This commit is contained in:
parent
8f5052a514
commit
4b03e6e776
22 changed files with 503 additions and 381 deletions
|
@ -149,8 +149,6 @@ add_library(core STATIC
|
||||||
hle/kernel/svc_results.h
|
hle/kernel/svc_results.h
|
||||||
hle/kernel/global_scheduler_context.cpp
|
hle/kernel/global_scheduler_context.cpp
|
||||||
hle/kernel/global_scheduler_context.h
|
hle/kernel/global_scheduler_context.h
|
||||||
hle/kernel/handle_table.cpp
|
|
||||||
hle/kernel/handle_table.h
|
|
||||||
hle/kernel/hle_ipc.cpp
|
hle/kernel/hle_ipc.cpp
|
||||||
hle/kernel/hle_ipc.h
|
hle/kernel/hle_ipc.h
|
||||||
hle/kernel/init/init_slab_setup.cpp
|
hle/kernel/init/init_slab_setup.cpp
|
||||||
|
@ -174,6 +172,8 @@ add_library(core STATIC
|
||||||
hle/kernel/k_condition_variable.h
|
hle/kernel/k_condition_variable.h
|
||||||
hle/kernel/k_event.cpp
|
hle/kernel/k_event.cpp
|
||||||
hle/kernel/k_event.h
|
hle/kernel/k_event.h
|
||||||
|
hle/kernel/k_handle_table.cpp
|
||||||
|
hle/kernel/k_handle_table.h
|
||||||
hle/kernel/k_light_condition_variable.h
|
hle/kernel/k_light_condition_variable.h
|
||||||
hle/kernel/k_light_lock.cpp
|
hle/kernel/k_light_lock.cpp
|
||||||
hle/kernel/k_light_lock.h
|
hle/kernel/k_light_lock.h
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/k_process.h"
|
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
|
||||||
#include "core/hle/kernel/svc_results.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
namespace {
|
|
||||||
constexpr u16 GetSlot(Handle handle) {
|
|
||||||
return static_cast<u16>(handle >> 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u16 GetGeneration(Handle handle) {
|
|
||||||
return static_cast<u16>(handle & 0x7FFF);
|
|
||||||
}
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} {
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleTable::~HandleTable() = default;
|
|
||||||
|
|
||||||
ResultCode HandleTable::SetSize(s32 handle_table_size) {
|
|
||||||
if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
|
|
||||||
LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT);
|
|
||||||
return ResultOutOfMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values less than or equal to zero indicate to use the maximum allowable
|
|
||||||
// size for the handle table in the actual kernel, so we ignore the given
|
|
||||||
// value in that case, since we assume this by default unless this function
|
|
||||||
// is called.
|
|
||||||
if (handle_table_size > 0) {
|
|
||||||
table_size = static_cast<u16>(handle_table_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
|
|
||||||
ASSERT(obj != nullptr);
|
|
||||||
|
|
||||||
const u16 slot = next_free_slot;
|
|
||||||
if (slot >= table_size) {
|
|
||||||
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
|
|
||||||
return ResultOutOfHandles;
|
|
||||||
}
|
|
||||||
next_free_slot = generations[slot];
|
|
||||||
|
|
||||||
const u16 generation = next_generation++;
|
|
||||||
|
|
||||||
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
|
|
||||||
// Horizon OS uses zero to represent an invalid handle, so skip to 1.
|
|
||||||
if (next_generation >= (1 << 15)) {
|
|
||||||
next_generation = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
generations[slot] = generation;
|
|
||||||
objects[slot] = obj;
|
|
||||||
obj->Open();
|
|
||||||
|
|
||||||
*out_handle = generation | (slot << 15);
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
|
|
||||||
auto object = GetObject(handle);
|
|
||||||
if (object.IsNull()) {
|
|
||||||
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
|
|
||||||
return ResultInvalidHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle out_handle{};
|
|
||||||
R_TRY(Add(&out_handle, object.GetPointerUnsafe()));
|
|
||||||
|
|
||||||
return MakeResult(out_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HandleTable::Remove(Handle handle) {
|
|
||||||
if (!IsValid(handle)) {
|
|
||||||
LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const u16 slot = GetSlot(handle);
|
|
||||||
|
|
||||||
if (objects[slot]) {
|
|
||||||
objects[slot]->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
objects[slot] = nullptr;
|
|
||||||
|
|
||||||
generations[slot] = next_free_slot;
|
|
||||||
next_free_slot = slot;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HandleTable::IsValid(Handle handle) const {
|
|
||||||
const std::size_t slot = GetSlot(handle);
|
|
||||||
const u16 generation = GetGeneration(handle);
|
|
||||||
const bool is_object_valid = (objects[slot] != nullptr);
|
|
||||||
return slot < table_size && is_object_valid && generations[slot] == generation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleTable::Clear() {
|
|
||||||
for (u16 i = 0; i < table_size; ++i) {
|
|
||||||
generations[i] = static_cast<u16>(i + 1);
|
|
||||||
objects[i] = nullptr;
|
|
||||||
}
|
|
||||||
next_free_slot = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
|
|
@ -1,212 +0,0 @@
|
||||||
// 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>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
|
||||||
#include "core/hle/kernel/k_spin_lock.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
|
||||||
#include "core/hle/result.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
|
|
||||||
class KernelCore;
|
|
||||||
|
|
||||||
enum KernelHandle : Handle {
|
|
||||||
InvalidHandle = 0,
|
|
||||||
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:
|
|
||||||
/// This is the maximum limit of handles allowed per process in Horizon
|
|
||||||
static constexpr std::size_t MAX_COUNT = 1024;
|
|
||||||
|
|
||||||
explicit HandleTable(KernelCore& kernel);
|
|
||||||
~HandleTable();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
bool Remove(Handle handle);
|
|
||||||
|
|
||||||
/// Checks if a handle is valid and points to an existing object.
|
|
||||||
bool IsValid(Handle handle) const;
|
|
||||||
|
|
||||||
template <typename T = KAutoObject>
|
|
||||||
KAutoObject* GetObjectImpl(Handle handle) const {
|
|
||||||
if (!IsValid(handle)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* obj = objects[static_cast<u16>(handle >> 15)];
|
|
||||||
return obj->DynamicCast<T*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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[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[static_cast<u16>(handle >> 15)];
|
|
||||||
return obj->DynamicCast<T*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Closes all handles held in this table.
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
|
|
||||||
// Try to convert and open all the handles.
|
|
||||||
size_t num_opened;
|
|
||||||
{
|
|
||||||
// Lock the table.
|
|
||||||
KScopedSpinLock lk(lock);
|
|
||||||
for (num_opened = 0; num_opened < num_handles; num_opened++) {
|
|
||||||
// Get the current handle.
|
|
||||||
const auto cur_handle = handles[num_opened];
|
|
||||||
|
|
||||||
// Get the object for the current handle.
|
|
||||||
KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
|
|
||||||
if (cur_object == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cast the current object to the desired type.
|
|
||||||
T* cur_t = cur_object->DynamicCast<T*>();
|
|
||||||
if (cur_t == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open a reference to the current object.
|
|
||||||
cur_t->Open();
|
|
||||||
out[num_opened] = cur_t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we converted every object, succeed.
|
|
||||||
if (num_opened == num_handles) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we didn't convert entry object, close the ones we opened.
|
|
||||||
for (size_t i = 0; i < num_opened; i++) {
|
|
||||||
out[i]->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Stores the Object referenced by the handle or null if the slot is empty.
|
|
||||||
std::array<KAutoObject*, MAX_COUNT> objects{};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
u16 next_generation = 1;
|
|
||||||
|
|
||||||
/// Head of the free slots linked list.
|
|
||||||
u16 next_free_slot = 0;
|
|
||||||
|
|
||||||
mutable KSpinLock lock;
|
|
||||||
|
|
||||||
/// Underlying kernel instance that this handle table operates under.
|
|
||||||
KernelCore& kernel;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Kernel
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_readable_event.h"
|
#include "core/hle/kernel/k_readable_event.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
|
@ -50,7 +50,7 @@ HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory&
|
||||||
|
|
||||||
HLERequestContext::~HLERequestContext() = default;
|
HLERequestContext::~HLERequestContext() = default;
|
||||||
|
|
||||||
void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf,
|
void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf,
|
||||||
bool incoming) {
|
bool incoming) {
|
||||||
IPC::RequestParser rp(src_cmdbuf);
|
IPC::RequestParser rp(src_cmdbuf);
|
||||||
command_header = rp.PopRaw<IPC::CommandHeader>();
|
command_header = rp.PopRaw<IPC::CommandHeader>();
|
||||||
|
@ -163,7 +163,7 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
|
||||||
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
|
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
|
||||||
u32_le* src_cmdbuf) {
|
u32_le* src_cmdbuf) {
|
||||||
ParseCommandBuffer(handle_table, src_cmdbuf, true);
|
ParseCommandBuffer(handle_table, src_cmdbuf, true);
|
||||||
if (command_header->type == IPC::CommandType::Close) {
|
if (command_header->type == IPC::CommandType::Close) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
|
#include "core/hle/kernel/svc_common.h"
|
||||||
|
|
||||||
union ResultCode;
|
union ResultCode;
|
||||||
|
|
||||||
|
@ -35,9 +36,9 @@ class ServiceFrameworkBase;
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class Domain;
|
class Domain;
|
||||||
class HandleTable;
|
|
||||||
class HLERequestContext;
|
class HLERequestContext;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
|
class KHandleTable;
|
||||||
class KProcess;
|
class KProcess;
|
||||||
class KServerSession;
|
class KServerSession;
|
||||||
class KThread;
|
class KThread;
|
||||||
|
@ -121,7 +122,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Populates this context with data from the requesting process/thread.
|
/// Populates this context with data from the requesting process/thread.
|
||||||
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
ResultCode PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
|
||||||
u32_le* src_cmdbuf);
|
u32_le* src_cmdbuf);
|
||||||
|
|
||||||
/// Writes data from this context back to the requesting process/thread.
|
/// Writes data from this context back to the requesting process/thread.
|
||||||
|
@ -267,7 +268,7 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class IPC::ResponseBuilder;
|
friend class IPC::ResponseBuilder;
|
||||||
|
|
||||||
void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
|
void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
|
||||||
|
|
||||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||||
Kernel::KServerSession* server_session{};
|
Kernel::KServerSession* server_session{};
|
||||||
|
|
|
@ -17,8 +17,6 @@ namespace Kernel {
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class KProcess;
|
class KProcess;
|
||||||
|
|
||||||
using Handle = u32;
|
|
||||||
|
|
||||||
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
|
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
|
||||||
NON_COPYABLE(CLASS); \
|
NON_COPYABLE(CLASS); \
|
||||||
NON_MOVEABLE(CLASS); \
|
NON_MOVEABLE(CLASS); \
|
||||||
|
|
|
@ -179,7 +179,7 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
|
||||||
|
|
||||||
KThread* thread_to_close = nullptr;
|
KThread* thread_to_close = nullptr;
|
||||||
if (can_access) {
|
if (can_access) {
|
||||||
if (prev_tag == InvalidHandle) {
|
if (prev_tag == Svc::InvalidHandle) {
|
||||||
// If nobody held the lock previously, we're all good.
|
// If nobody held the lock previously, we're all good.
|
||||||
thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
||||||
thread->Wakeup();
|
thread->Wakeup();
|
||||||
|
|
135
src/core/hle/kernel/k_handle_table.cpp
Normal file
135
src/core/hle/kernel/k_handle_table.cpp
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
// Copyright 2021 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
|
||||||
|
KHandleTable ::~KHandleTable() = default;
|
||||||
|
|
||||||
|
ResultCode KHandleTable::Finalize() {
|
||||||
|
// Get the table and clear our record of it.
|
||||||
|
u16 saved_table_size = 0;
|
||||||
|
{
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
|
std::swap(m_table_size, saved_table_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close and free all entries.
|
||||||
|
for (size_t i = 0; i < saved_table_size; i++) {
|
||||||
|
if (KAutoObject* obj = m_objects[i]; obj != nullptr) {
|
||||||
|
obj->Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KHandleTable::Remove(Handle handle) {
|
||||||
|
// Don't allow removal of a pseudo-handle.
|
||||||
|
if (Svc::IsPseudoHandle(handle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles must not have reserved bits set.
|
||||||
|
const auto handle_pack = HandlePack(handle);
|
||||||
|
if (handle_pack.reserved != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the object and free the entry.
|
||||||
|
KAutoObject* obj = nullptr;
|
||||||
|
{
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
|
if (this->IsValidHandle(handle)) {
|
||||||
|
const auto index = handle_pack.index;
|
||||||
|
|
||||||
|
obj = m_objects[index];
|
||||||
|
this->FreeEntry(index);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the object.
|
||||||
|
obj->Close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
|
// Never exceed our capacity.
|
||||||
|
R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
|
||||||
|
|
||||||
|
// Allocate entry, set output handle.
|
||||||
|
{
|
||||||
|
const auto linear_id = this->AllocateLinearId();
|
||||||
|
const auto index = this->AllocateEntry();
|
||||||
|
|
||||||
|
m_entry_infos[index].info = {.linear_id = linear_id, .type = type};
|
||||||
|
m_objects[index] = obj;
|
||||||
|
|
||||||
|
obj->Open();
|
||||||
|
|
||||||
|
*out_handle = EncodeHandle(static_cast<u16>(index), linear_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode KHandleTable::Reserve(Handle* out_handle) {
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
|
// Never exceed our capacity.
|
||||||
|
R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
|
||||||
|
|
||||||
|
*out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId());
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KHandleTable::Unreserve(Handle handle) {
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
|
// Unpack the handle.
|
||||||
|
const auto handle_pack = HandlePack(handle);
|
||||||
|
const auto index = handle_pack.index;
|
||||||
|
const auto linear_id = handle_pack.linear_id;
|
||||||
|
const auto reserved = handle_pack.reserved;
|
||||||
|
ASSERT(reserved == 0);
|
||||||
|
ASSERT(linear_id != 0);
|
||||||
|
|
||||||
|
if (index < m_table_size) {
|
||||||
|
// NOTE: This code does not check the linear id.
|
||||||
|
ASSERT(m_objects[index] == nullptr);
|
||||||
|
this->FreeEntry(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) {
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
|
// Unpack the handle.
|
||||||
|
const auto handle_pack = HandlePack(handle);
|
||||||
|
const auto index = handle_pack.index;
|
||||||
|
const auto linear_id = handle_pack.linear_id;
|
||||||
|
const auto reserved = handle_pack.reserved;
|
||||||
|
ASSERT(reserved == 0);
|
||||||
|
ASSERT(linear_id != 0);
|
||||||
|
|
||||||
|
if (index < m_table_size) {
|
||||||
|
// Set the entry.
|
||||||
|
ASSERT(m_objects[index] == nullptr);
|
||||||
|
|
||||||
|
m_entry_infos[index].info = {.linear_id = static_cast<u16>(linear_id), .type = type};
|
||||||
|
m_objects[index] = obj;
|
||||||
|
|
||||||
|
obj->Open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
309
src/core/hle/kernel/k_handle_table.h
Normal file
309
src/core/hle/kernel/k_handle_table.h
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
// Copyright 2021 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/bit_field.h"
|
||||||
|
#include "common/bit_util.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
|
#include "core/hle/kernel/k_spin_lock.h"
|
||||||
|
#include "core/hle/kernel/k_thread.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/svc_common.h"
|
||||||
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
|
class KHandleTable {
|
||||||
|
NON_COPYABLE(KHandleTable);
|
||||||
|
NON_MOVEABLE(KHandleTable);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr size_t MaxTableSize = 1024;
|
||||||
|
|
||||||
|
private:
|
||||||
|
union HandlePack {
|
||||||
|
u32 raw;
|
||||||
|
BitField<0, 15, u32> index;
|
||||||
|
BitField<15, 15, u32> linear_id;
|
||||||
|
BitField<30, 2, u32> reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr u16 MinLinearId = 1;
|
||||||
|
static constexpr u16 MaxLinearId = 0x7FFF;
|
||||||
|
|
||||||
|
static constexpr Handle EncodeHandle(u16 index, u16 linear_id) {
|
||||||
|
HandlePack handle{};
|
||||||
|
handle.index.Assign(index);
|
||||||
|
handle.linear_id.Assign(linear_id);
|
||||||
|
handle.reserved.Assign(0);
|
||||||
|
return handle.raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
union EntryInfo {
|
||||||
|
struct {
|
||||||
|
u16 linear_id;
|
||||||
|
u16 type;
|
||||||
|
} info;
|
||||||
|
s32 next_free_index;
|
||||||
|
|
||||||
|
constexpr u16 GetLinearId() const {
|
||||||
|
return info.linear_id;
|
||||||
|
}
|
||||||
|
constexpr u16 GetType() const {
|
||||||
|
return info.type;
|
||||||
|
}
|
||||||
|
constexpr s32 GetNextFreeIndex() const {
|
||||||
|
return next_free_index;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<EntryInfo, MaxTableSize> m_entry_infos{};
|
||||||
|
std::array<KAutoObject*, MaxTableSize> m_objects{};
|
||||||
|
s32 m_free_head_index{-1};
|
||||||
|
u16 m_table_size{};
|
||||||
|
u16 m_max_count{};
|
||||||
|
u16 m_next_linear_id{MinLinearId};
|
||||||
|
u16 m_count{};
|
||||||
|
mutable KSpinLock m_lock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit KHandleTable(KernelCore& kernel_);
|
||||||
|
~KHandleTable();
|
||||||
|
|
||||||
|
constexpr ResultCode Initialize(s32 size) {
|
||||||
|
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
|
||||||
|
|
||||||
|
// Initialize all fields.
|
||||||
|
m_max_count = 0;
|
||||||
|
m_table_size = static_cast<u16>((size <= 0) ? MaxTableSize : size);
|
||||||
|
m_next_linear_id = MinLinearId;
|
||||||
|
m_count = 0;
|
||||||
|
m_free_head_index = -1;
|
||||||
|
|
||||||
|
// Free all entries.
|
||||||
|
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
|
||||||
|
m_objects[i] = nullptr;
|
||||||
|
m_entry_infos[i].next_free_index = i - 1;
|
||||||
|
m_free_head_index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t GetTableSize() const {
|
||||||
|
return m_table_size;
|
||||||
|
}
|
||||||
|
constexpr size_t GetCount() const {
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
constexpr size_t GetMaxCount() const {
|
||||||
|
return m_max_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode Finalize();
|
||||||
|
bool Remove(Handle handle);
|
||||||
|
|
||||||
|
template <typename T = KAutoObject>
|
||||||
|
KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
|
||||||
|
// Lock and look up in table.
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, KAutoObject>::value) {
|
||||||
|
return this->GetObjectImpl(handle);
|
||||||
|
} else {
|
||||||
|
if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) {
|
||||||
|
return obj->DynamicCast<T*>();
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = KAutoObject>
|
||||||
|
KScopedAutoObject<T> GetObject(Handle handle) const {
|
||||||
|
// Handle pseudo-handles.
|
||||||
|
if constexpr (std::derived_from<KProcess, T>) {
|
||||||
|
if (handle == Svc::PseudoHandle::CurrentProcess) {
|
||||||
|
auto* const cur_process = kernel.CurrentProcess();
|
||||||
|
ASSERT(cur_process != nullptr);
|
||||||
|
return cur_process;
|
||||||
|
}
|
||||||
|
} else if constexpr (std::derived_from<KThread, T>) {
|
||||||
|
if (handle == Svc::PseudoHandle::CurrentThread) {
|
||||||
|
auto* const cur_thread = GetCurrentThreadPointer(kernel);
|
||||||
|
ASSERT(cur_thread != nullptr);
|
||||||
|
return cur_thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->template GetObjectWithoutPseudoHandle<T>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode Reserve(Handle* out_handle);
|
||||||
|
void Unreserve(Handle handle);
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Register(Handle handle, T* obj) {
|
||||||
|
static_assert(std::is_base_of<KAutoObject, T>::value);
|
||||||
|
return this->Register(handle, obj, obj->GetTypeObj().GetClassToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
|
||||||
|
// Try to convert and open all the handles.
|
||||||
|
size_t num_opened;
|
||||||
|
{
|
||||||
|
// Lock the table.
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
for (num_opened = 0; num_opened < num_handles; num_opened++) {
|
||||||
|
// Get the current handle.
|
||||||
|
const auto cur_handle = handles[num_opened];
|
||||||
|
|
||||||
|
// Get the object for the current handle.
|
||||||
|
KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
|
||||||
|
if (cur_object == nullptr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast the current object to the desired type.
|
||||||
|
T* cur_t = cur_object->DynamicCast<T*>();
|
||||||
|
if (cur_t == nullptr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a reference to the current object.
|
||||||
|
cur_t->Open();
|
||||||
|
out[num_opened] = cur_t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we converted every object, succeed.
|
||||||
|
if (num_opened == num_handles) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't convert entry object, close the ones we opened.
|
||||||
|
for (size_t i = 0; i < num_opened; i++) {
|
||||||
|
out[i]->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type);
|
||||||
|
void Register(Handle handle, KAutoObject* obj, u16 type);
|
||||||
|
|
||||||
|
constexpr s32 AllocateEntry() {
|
||||||
|
ASSERT(m_count < m_table_size);
|
||||||
|
|
||||||
|
const auto index = m_free_head_index;
|
||||||
|
|
||||||
|
m_free_head_index = m_entry_infos[index].GetNextFreeIndex();
|
||||||
|
|
||||||
|
m_max_count = std::max(m_max_count, ++m_count);
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void FreeEntry(s32 index) {
|
||||||
|
ASSERT(m_count > 0);
|
||||||
|
|
||||||
|
m_objects[index] = nullptr;
|
||||||
|
m_entry_infos[index].next_free_index = m_free_head_index;
|
||||||
|
|
||||||
|
m_free_head_index = index;
|
||||||
|
|
||||||
|
--m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr u16 AllocateLinearId() {
|
||||||
|
const u16 id = m_next_linear_id++;
|
||||||
|
if (m_next_linear_id > MaxLinearId) {
|
||||||
|
m_next_linear_id = MinLinearId;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsValidHandle(Handle handle) const {
|
||||||
|
// Unpack the handle.
|
||||||
|
const auto handle_pack = HandlePack(handle);
|
||||||
|
const auto raw_value = handle_pack.raw;
|
||||||
|
const auto index = handle_pack.index;
|
||||||
|
const auto linear_id = handle_pack.linear_id;
|
||||||
|
const auto reserved = handle_pack.reserved;
|
||||||
|
ASSERT(reserved == 0);
|
||||||
|
|
||||||
|
// Validate our indexing information.
|
||||||
|
if (raw_value == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (linear_id == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (index >= m_table_size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that there's an object, and our serial id is correct.
|
||||||
|
if (m_objects[index] == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (m_entry_infos[index].GetLinearId() != linear_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr KAutoObject* GetObjectImpl(Handle handle) const {
|
||||||
|
// Handles must not have reserved bits set.
|
||||||
|
const auto handle_pack = HandlePack(handle);
|
||||||
|
if (handle_pack.reserved != 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->IsValidHandle(handle)) {
|
||||||
|
return m_objects[handle_pack.index];
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const {
|
||||||
|
|
||||||
|
// Index must be in bounds.
|
||||||
|
if (index >= m_table_size) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure entry has an object.
|
||||||
|
if (KAutoObject* obj = m_objects[index]; obj != nullptr) {
|
||||||
|
*out_handle = EncodeHandle(static_cast<u16>(index), m_entry_infos[index].GetLinearId());
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
KernelCore& kernel;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -354,7 +354,7 @@ ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
|
||||||
tls_region_address = CreateTLSRegion();
|
tls_region_address = CreateTLSRegion();
|
||||||
memory_reservation.Commit();
|
memory_reservation.Commit();
|
||||||
|
|
||||||
return handle_table.SetSize(capabilities.GetHandleTableSize());
|
return handle_table.Initialize(capabilities.GetHandleTableSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
|
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
|
||||||
|
|
|
@ -11,10 +11,10 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/k_address_arbiter.h"
|
#include "core/hle/kernel/k_address_arbiter.h"
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
#include "core/hle/kernel/k_condition_variable.h"
|
#include "core/hle/kernel/k_condition_variable.h"
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/process_capability.h"
|
#include "core/hle/kernel/process_capability.h"
|
||||||
#include "core/hle/kernel/slab_helpers.h"
|
#include "core/hle/kernel/slab_helpers.h"
|
||||||
|
@ -104,12 +104,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a reference to the process' handle table.
|
/// Gets a reference to the process' handle table.
|
||||||
HandleTable& GetHandleTable() {
|
KHandleTable& GetHandleTable() {
|
||||||
return handle_table;
|
return handle_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a const reference to the process' handle table.
|
/// Gets a const reference to the process' handle table.
|
||||||
const HandleTable& GetHandleTable() const {
|
const KHandleTable& GetHandleTable() const {
|
||||||
return handle_table;
|
return handle_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ private:
|
||||||
u64 total_process_running_time_ticks = 0;
|
u64 total_process_running_time_ticks = 0;
|
||||||
|
|
||||||
/// Per-process handle table for storing created object handles in.
|
/// Per-process handle table for storing created object handles in.
|
||||||
HandleTable handle_table;
|
KHandleTable handle_table;
|
||||||
|
|
||||||
/// Per-process address arbiter.
|
/// Per-process address arbiter.
|
||||||
KAddressArbiter address_arbiter;
|
KAddressArbiter address_arbiter;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
@ -17,7 +17,7 @@ namespace Kernel {
|
||||||
|
|
||||||
class [[nodiscard]] KScopedSchedulerLockAndSleep {
|
class [[nodiscard]] KScopedSchedulerLockAndSleep {
|
||||||
public:
|
public:
|
||||||
explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout)
|
explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout)
|
||||||
: kernel(kernel), thread(t), timeout_tick(timeout) {
|
: kernel(kernel), thread(t), timeout_tick(timeout) {
|
||||||
// Lock the scheduler.
|
// Lock the scheduler.
|
||||||
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
|
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/k_client_port.h"
|
#include "core/hle/kernel/k_client_port.h"
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_server_session.h"
|
#include "core/hle/kernel/k_server_session.h"
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/cpu_manager.h"
|
#include "core/cpu_manager.h"
|
||||||
#include "core/hardware_properties.h"
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/k_condition_variable.h"
|
#include "core/hle/kernel/k_condition_variable.h"
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_memory_layout.h"
|
#include "core/hle/kernel/k_memory_layout.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_resource_limit.h"
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
|
|
|
@ -26,9 +26,9 @@
|
||||||
#include "core/cpu_manager.h"
|
#include "core/cpu_manager.h"
|
||||||
#include "core/device_memory.h"
|
#include "core/device_memory.h"
|
||||||
#include "core/hardware_properties.h"
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/init/init_slab_setup.h"
|
#include "core/hle/kernel/init/init_slab_setup.h"
|
||||||
#include "core/hle/kernel/k_client_port.h"
|
#include "core/hle/kernel/k_client_port.h"
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_memory_layout.h"
|
#include "core/hle/kernel/k_memory_layout.h"
|
||||||
#include "core/hle/kernel/k_memory_manager.h"
|
#include "core/hle/kernel/k_memory_manager.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
@ -52,8 +52,7 @@ namespace Kernel {
|
||||||
|
|
||||||
struct KernelCore::Impl {
|
struct KernelCore::Impl {
|
||||||
explicit Impl(Core::System& system, KernelCore& kernel)
|
explicit Impl(Core::System& system, KernelCore& kernel)
|
||||||
: time_manager{system}, global_handle_table{kernel},
|
: time_manager{system}, object_list_container{kernel}, system{system} {}
|
||||||
object_list_container{kernel}, system{system} {}
|
|
||||||
|
|
||||||
void SetMulticore(bool is_multicore) {
|
void SetMulticore(bool is_multicore) {
|
||||||
this->is_multicore = is_multicore;
|
this->is_multicore = is_multicore;
|
||||||
|
@ -61,6 +60,7 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
void Initialize(KernelCore& kernel) {
|
void Initialize(KernelCore& kernel) {
|
||||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||||
|
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
|
||||||
|
|
||||||
service_thread_manager =
|
service_thread_manager =
|
||||||
std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
|
std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
|
||||||
|
@ -118,7 +118,7 @@ struct KernelCore::Impl {
|
||||||
current_process = nullptr;
|
current_process = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
global_handle_table.Clear();
|
global_handle_table.reset();
|
||||||
|
|
||||||
preemption_event = nullptr;
|
preemption_event = nullptr;
|
||||||
|
|
||||||
|
@ -648,7 +648,7 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
// This is the kernel's handle table or supervisor handle table which
|
// This is the kernel's handle table or supervisor handle table which
|
||||||
// stores all the objects in place.
|
// stores all the objects in place.
|
||||||
HandleTable global_handle_table;
|
std::unique_ptr<KHandleTable> global_handle_table;
|
||||||
|
|
||||||
KAutoObjectWithListContainer object_list_container;
|
KAutoObjectWithListContainer object_list_container;
|
||||||
|
|
||||||
|
@ -722,7 +722,7 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
|
KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
|
||||||
return impl->global_handle_table.GetObject<KThread>(handle);
|
return impl->global_handle_table->GetObject<KThread>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::AppendNewProcess(KProcess* process) {
|
void KernelCore::AppendNewProcess(KProcess* process) {
|
||||||
|
@ -876,12 +876,12 @@ u64 KernelCore::CreateNewUserProcessID() {
|
||||||
return impl->next_user_process_id++;
|
return impl->next_user_process_id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::HandleTable& KernelCore::GlobalHandleTable() {
|
KHandleTable& KernelCore::GlobalHandleTable() {
|
||||||
return impl->global_handle_table;
|
return *impl->global_handle_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Kernel::HandleTable& KernelCore::GlobalHandleTable() const {
|
const KHandleTable& KernelCore::GlobalHandleTable() const {
|
||||||
return impl->global_handle_table;
|
return *impl->global_handle_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::RegisterCoreThread(std::size_t core_id) {
|
void KernelCore::RegisterCoreThread(std::size_t core_id) {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
#include "core/hle/kernel/k_slab_heap.h"
|
#include "core/hle/kernel/k_slab_heap.h"
|
||||||
#include "core/hle/kernel/memory_types.h"
|
#include "core/hle/kernel/memory_types.h"
|
||||||
|
#include "core/hle/kernel/svc_common.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class CPUInterruptHandler;
|
class CPUInterruptHandler;
|
||||||
|
@ -30,10 +31,10 @@ namespace Kernel {
|
||||||
|
|
||||||
class KClientPort;
|
class KClientPort;
|
||||||
class GlobalSchedulerContext;
|
class GlobalSchedulerContext;
|
||||||
class HandleTable;
|
|
||||||
class KAutoObjectWithListContainer;
|
class KAutoObjectWithListContainer;
|
||||||
class KClientSession;
|
class KClientSession;
|
||||||
class KEvent;
|
class KEvent;
|
||||||
|
class KHandleTable;
|
||||||
class KLinkedListNode;
|
class KLinkedListNode;
|
||||||
class KMemoryManager;
|
class KMemoryManager;
|
||||||
class KPort;
|
class KPort;
|
||||||
|
@ -308,10 +309,10 @@ private:
|
||||||
u64 CreateNewThreadID();
|
u64 CreateNewThreadID();
|
||||||
|
|
||||||
/// Provides a reference to the global handle table.
|
/// Provides a reference to the global handle table.
|
||||||
Kernel::HandleTable& GlobalHandleTable();
|
KHandleTable& GlobalHandleTable();
|
||||||
|
|
||||||
/// Provides a const reference to the global handle table.
|
/// Provides a const reference to the global handle table.
|
||||||
const Kernel::HandleTable& GlobalHandleTable() const;
|
const KHandleTable& GlobalHandleTable() const;
|
||||||
|
|
||||||
struct Impl;
|
struct Impl;
|
||||||
std::unique_ptr<Impl> impl;
|
std::unique_ptr<Impl> impl;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_page_table.h"
|
#include "core/hle/kernel/k_page_table.h"
|
||||||
#include "core/hle/kernel/process_capability.h"
|
#include "core/hle/kernel/process_capability.h"
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
@ -99,7 +99,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() {
|
||||||
interrupt_capabilities.set();
|
interrupt_capabilities.set();
|
||||||
|
|
||||||
// Allow using the maximum possible amount of handles
|
// Allow using the maximum possible amount of handles
|
||||||
handle_table_size = static_cast<s32>(HandleTable::MAX_COUNT);
|
handle_table_size = static_cast<s32>(KHandleTable::MaxTableSize);
|
||||||
|
|
||||||
// Allow all debugging capabilities.
|
// Allow all debugging capabilities.
|
||||||
is_debuggable = true;
|
is_debuggable = true;
|
||||||
|
|
|
@ -21,12 +21,12 @@
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/cpu_manager.h"
|
#include "core/cpu_manager.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/k_address_arbiter.h"
|
#include "core/hle/kernel/k_address_arbiter.h"
|
||||||
#include "core/hle/kernel/k_client_port.h"
|
#include "core/hle/kernel/k_client_port.h"
|
||||||
#include "core/hle/kernel/k_client_session.h"
|
#include "core/hle/kernel/k_client_session.h"
|
||||||
#include "core/hle/kernel/k_condition_variable.h"
|
#include "core/hle/kernel/k_condition_variable.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_memory_block.h"
|
#include "core/hle/kernel/k_memory_block.h"
|
||||||
#include "core/hle/kernel/k_memory_layout.h"
|
#include "core/hle/kernel/k_memory_layout.h"
|
||||||
#include "core/hle/kernel/k_page_table.h"
|
#include "core/hle/kernel/k_page_table.h"
|
||||||
|
@ -839,10 +839,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
KProcess* const current_process = system.Kernel().CurrentProcess();
|
KProcess* const current_process = system.Kernel().CurrentProcess();
|
||||||
HandleTable& handle_table = current_process->GetHandleTable();
|
KHandleTable& handle_table = current_process->GetHandleTable();
|
||||||
const auto resource_limit = current_process->GetResourceLimit();
|
const auto resource_limit = current_process->GetResourceLimit();
|
||||||
if (!resource_limit) {
|
if (!resource_limit) {
|
||||||
*result = KernelHandle::InvalidHandle;
|
*result = Svc::InvalidHandle;
|
||||||
// Yes, the kernel considers this a successful operation.
|
// Yes, the kernel considers this a successful operation.
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1993,7 +1993,7 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
|
LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
|
||||||
|
|
||||||
// Get the current handle table.
|
// Get the current handle table.
|
||||||
const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||||
|
|
||||||
// Get the writable event.
|
// Get the writable event.
|
||||||
KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
|
KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
|
||||||
|
|
|
@ -6,9 +6,24 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
using Handle = u32;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
|
|
||||||
constexpr s32 ArgumentHandleCountMax = 0x40;
|
constexpr s32 ArgumentHandleCountMax = 0x40;
|
||||||
constexpr u32 HandleWaitMask{1u << 30};
|
constexpr u32 HandleWaitMask{1u << 30};
|
||||||
|
|
||||||
|
constexpr inline Handle InvalidHandle = Handle(0);
|
||||||
|
|
||||||
|
enum PseudoHandle : Handle {
|
||||||
|
CurrentThread = 0xFFFF8000,
|
||||||
|
CurrentProcess = 0xFFFF8001,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool IsPseudoHandle(const Handle& handle) {
|
||||||
|
return handle == PseudoHandle::CurrentProcess || handle == PseudoHandle::CurrentThread;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel::Svc
|
} // namespace Kernel::Svc
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
|
||||||
#include "core/hle/kernel/k_class_token.h"
|
#include "core/hle/kernel/k_class_token.h"
|
||||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_readable_event.h"
|
#include "core/hle/kernel/k_readable_event.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
|
@ -115,7 +115,7 @@ QString WaitTreeText::GetText() const {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table)
|
WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table)
|
||||||
: mutex_address(mutex_address) {
|
: mutex_address(mutex_address) {
|
||||||
mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
|
mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
|
||||||
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
|
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
|
||||||
|
|
|
@ -14,11 +14,12 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
|
#include "core/hle/kernel/svc_common.h"
|
||||||
|
|
||||||
class EmuThread;
|
class EmuThread;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class HandleTable;
|
class KHandleTable;
|
||||||
class KReadableEvent;
|
class KReadableEvent;
|
||||||
class KSynchronizationObject;
|
class KSynchronizationObject;
|
||||||
class KThread;
|
class KThread;
|
||||||
|
@ -74,7 +75,7 @@ public:
|
||||||
class WaitTreeMutexInfo : public WaitTreeExpandableItem {
|
class WaitTreeMutexInfo : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table);
|
explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table);
|
||||||
~WaitTreeMutexInfo() override;
|
~WaitTreeMutexInfo() override;
|
||||||
|
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
|
|
Loading…
Reference in a new issue