diff options
| -rw-r--r-- | src/core/hle/kernel/errors.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/handle_table.cpp | 26 | ||||
| -rw-r--r-- | src/core/hle/kernel/handle_table.h | 21 | ||||
| -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, 54 insertions, 10 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 cd3508fa9..84a9ca7fc 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -28,17 +28,33 @@ HandleTable::HandleTable() {  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. @@ -79,7 +95,7 @@ bool HandleTable::IsValid(Handle handle) const {      std::size_t slot = GetSlot(handle);      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 { @@ -96,7 +112,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 5fa55c783..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,6 +118,13 @@ 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.       */ 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; | 
