diff options
Diffstat (limited to 'src/core/hle')
-rw-r--r-- | src/core/hle/kernel/errors.h | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/handle_table.cpp | 40 | ||||
-rw-r--r-- | src/core/hle/kernel/handle_table.h | 25 | ||||
-rw-r--r-- | src/core/hle/kernel/process.cpp | 8 | ||||
-rw-r--r-- | src/core/hle/kernel/process_capability.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/kernel/process_capability.h | 4 |
6 files changed, 63 insertions, 19 deletions
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index d17eb0cb6..8097b3863 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -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_SIZE{ErrorModule::Kernel, 101}; 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_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106}; constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108}; diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index c8acde5b1..bdfaa977f 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -14,32 +14,47 @@ namespace Kernel { namespace { constexpr u16 GetSlot(Handle handle) { - return handle >> 15; + return static_cast<u16>(handle >> 15); } constexpr u16 GetGeneration(Handle handle) { - return handle & 0x7FFF; + return static_cast<u16>(handle & 0x7FFF); } } // Anonymous namespace HandleTable::HandleTable() { - next_generation = 1; Clear(); } 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) { DEBUG_ASSERT(obj != nullptr); - u16 slot = next_free_slot; - if (slot >= generations.size()) { + const u16 slot = next_free_slot; + if (slot >= table_size) { LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); return ERR_HANDLE_TABLE_FULL; } 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. // 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) { - if (!IsValid(handle)) + if (!IsValid(handle)) { return ERR_INVALID_HANDLE; + } - u16 slot = GetSlot(handle); + const u16 slot = GetSlot(handle); objects[slot] = nullptr; @@ -77,10 +93,10 @@ ResultCode HandleTable::Close(Handle handle) { } bool HandleTable::IsValid(Handle handle) const { - std::size_t slot = GetSlot(handle); - u16 generation = GetGeneration(handle); + const std::size_t slot = GetSlot(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 { @@ -97,7 +113,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { } void HandleTable::Clear() { - for (u16 i = 0; i < MAX_COUNT; ++i) { + for (u16 i = 0; i < table_size; ++i) { generations[i] = i + 1; objects[i] = nullptr; } diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 89a3bc740..44901391b 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -50,6 +50,20 @@ public: ~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. * @return The created Handle or one of the following errors: * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. @@ -104,13 +118,20 @@ private: 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; + u16 next_generation = 1; /// Head of the free slots linked list. - u16 next_free_slot; + u16 next_free_slot = 0; }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c5aa19afa..8009150e0 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -99,7 +99,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { vm_manager.Reset(metadata.GetAddressSpaceType()); 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) { diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 3a2164b25..583e35b79 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -96,7 +96,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() { interrupt_capabilities.set(); // 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. is_debuggable = true; @@ -337,7 +337,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) { return ERR_RESERVED_VALUE; } - handle_table_size = (flags >> 16) & 0x3FF; + handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h index fbc8812a3..5cdd80747 100644 --- a/src/core/hle/kernel/process_capability.h +++ b/src/core/hle/kernel/process_capability.h @@ -156,7 +156,7 @@ public: } /// Gets the number of total allowable handles for the process' handle table. - u32 GetHandleTableSize() const { + s32 GetHandleTableSize() const { return handle_table_size; } @@ -252,7 +252,7 @@ private: u64 core_mask = 0; u64 priority_mask = 0; - u32 handle_table_size = 0; + s32 handle_table_size = 0; u32 kernel_version = 0; ProgramType program_type = ProgramType::SysModule; |