Merge pull request #2161 from lioncash/handle-table
kernel/handle_table: Allow process capabilities to limit the handle table size
This commit is contained in:
commit
eb5a3dd1c7
@ -14,6 +14,7 @@ constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
|
|||||||
constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
|
constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
|
||||||
constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
|
constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
|
constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
|
||||||
|
constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104};
|
||||||
constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
|
constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
|
constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
|
||||||
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
|
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
|
||||||
|
@ -14,32 +14,47 @@
|
|||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr u16 GetSlot(Handle handle) {
|
constexpr u16 GetSlot(Handle handle) {
|
||||||
return handle >> 15;
|
return static_cast<u16>(handle >> 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u16 GetGeneration(Handle handle) {
|
constexpr u16 GetGeneration(Handle handle) {
|
||||||
return handle & 0x7FFF;
|
return static_cast<u16>(handle & 0x7FFF);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
HandleTable::HandleTable() {
|
HandleTable::HandleTable() {
|
||||||
next_generation = 1;
|
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleTable::~HandleTable() = default;
|
HandleTable::~HandleTable() = default;
|
||||||
|
|
||||||
|
ResultCode HandleTable::SetSize(s32 handle_table_size) {
|
||||||
|
if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
|
||||||
|
return ERR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
|
ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
|
||||||
DEBUG_ASSERT(obj != nullptr);
|
DEBUG_ASSERT(obj != nullptr);
|
||||||
|
|
||||||
u16 slot = next_free_slot;
|
const u16 slot = next_free_slot;
|
||||||
if (slot >= generations.size()) {
|
if (slot >= table_size) {
|
||||||
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
|
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
|
||||||
return ERR_HANDLE_TABLE_FULL;
|
return ERR_HANDLE_TABLE_FULL;
|
||||||
}
|
}
|
||||||
next_free_slot = generations[slot];
|
next_free_slot = generations[slot];
|
||||||
|
|
||||||
u16 generation = next_generation++;
|
const u16 generation = next_generation++;
|
||||||
|
|
||||||
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
|
// 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.
|
// Horizon OS uses zero to represent an invalid handle, so skip to 1.
|
||||||
@ -64,10 +79,11 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultCode HandleTable::Close(Handle handle) {
|
ResultCode HandleTable::Close(Handle handle) {
|
||||||
if (!IsValid(handle))
|
if (!IsValid(handle)) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
u16 slot = GetSlot(handle);
|
const u16 slot = GetSlot(handle);
|
||||||
|
|
||||||
objects[slot] = nullptr;
|
objects[slot] = nullptr;
|
||||||
|
|
||||||
@ -77,10 +93,10 @@ ResultCode HandleTable::Close(Handle handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HandleTable::IsValid(Handle handle) const {
|
bool HandleTable::IsValid(Handle handle) const {
|
||||||
std::size_t slot = GetSlot(handle);
|
const std::size_t slot = GetSlot(handle);
|
||||||
u16 generation = GetGeneration(handle);
|
const u16 generation = GetGeneration(handle);
|
||||||
|
|
||||||
return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
|
return slot < table_size && objects[slot] != nullptr && generations[slot] == generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
|
SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
|
||||||
@ -97,7 +113,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleTable::Clear() {
|
void HandleTable::Clear() {
|
||||||
for (u16 i = 0; i < MAX_COUNT; ++i) {
|
for (u16 i = 0; i < table_size; ++i) {
|
||||||
generations[i] = i + 1;
|
generations[i] = i + 1;
|
||||||
objects[i] = nullptr;
|
objects[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,20 @@ public:
|
|||||||
HandleTable();
|
HandleTable();
|
||||||
~HandleTable();
|
~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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates a handle for the given object.
|
* Allocates a handle for the given object.
|
||||||
* @return The created Handle or one of the following errors:
|
* @return The created Handle or one of the following errors:
|
||||||
@ -103,14 +117,21 @@ private:
|
|||||||
*/
|
*/
|
||||||
std::array<u16, MAX_COUNT> generations;
|
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
|
* 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.
|
* created, and wraps around to 1 when it hits 0x8000.
|
||||||
*/
|
*/
|
||||||
u16 next_generation;
|
u16 next_generation = 1;
|
||||||
|
|
||||||
/// Head of the free slots linked list.
|
/// Head of the free slots linked list.
|
||||||
u16 next_free_slot;
|
u16 next_free_slot = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -99,7 +99,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
|||||||
vm_manager.Reset(metadata.GetAddressSpaceType());
|
vm_manager.Reset(metadata.GetAddressSpaceType());
|
||||||
|
|
||||||
const auto& caps = metadata.GetKernelCapabilities();
|
const auto& caps = metadata.GetKernelCapabilities();
|
||||||
return capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager);
|
const auto capability_init_result =
|
||||||
|
capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager);
|
||||||
|
if (capability_init_result.IsError()) {
|
||||||
|
return capability_init_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle_table.SetSize(capabilities.GetHandleTableSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
|
void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
|
||||||
|
@ -96,7 +96,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<u32>(HandleTable::MAX_COUNT);
|
handle_table_size = static_cast<s32>(HandleTable::MAX_COUNT);
|
||||||
|
|
||||||
// Allow all debugging capabilities.
|
// Allow all debugging capabilities.
|
||||||
is_debuggable = true;
|
is_debuggable = true;
|
||||||
@ -337,7 +337,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
|
|||||||
return ERR_RESERVED_VALUE;
|
return ERR_RESERVED_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_table_size = (flags >> 16) & 0x3FF;
|
handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of total allowable handles for the process' handle table.
|
/// Gets the number of total allowable handles for the process' handle table.
|
||||||
u32 GetHandleTableSize() const {
|
s32 GetHandleTableSize() const {
|
||||||
return handle_table_size;
|
return handle_table_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ private:
|
|||||||
u64 core_mask = 0;
|
u64 core_mask = 0;
|
||||||
u64 priority_mask = 0;
|
u64 priority_mask = 0;
|
||||||
|
|
||||||
u32 handle_table_size = 0;
|
s32 handle_table_size = 0;
|
||||||
u32 kernel_version = 0;
|
u32 kernel_version = 0;
|
||||||
|
|
||||||
ProgramType program_type = ProgramType::SysModule;
|
ProgramType program_type = ProgramType::SysModule;
|
||||||
|
Loading…
Reference in New Issue
Block a user