summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/ipc_helpers.h2
-rw-r--r--src/core/hle/kernel/address_arbiter.h1
-rw-r--r--src/core/hle/kernel/client_port.h1
-rw-r--r--src/core/hle/kernel/client_session.h3
-rw-r--r--src/core/hle/kernel/handle_table.cpp97
-rw-r--r--src/core/hle/kernel/handle_table.h126
-rw-r--r--src/core/hle/kernel/kernel.cpp85
-rw-r--r--src/core/hle/kernel/kernel.h116
-rw-r--r--src/core/hle/kernel/memory.cpp1
-rw-r--r--src/core/hle/kernel/resource_limit.cpp1
-rw-r--r--src/core/hle/kernel/semaphore.h1
-rw-r--r--src/core/hle/kernel/server_session.h2
-rw-r--r--src/core/hle/kernel/thread.cpp1
-rw-r--r--src/core/hle/kernel/timer.cpp1
-rw-r--r--src/core/hle/service/apt/apt.h2
-rw-r--r--src/core/hle/service/service.h1
-rw-r--r--src/core/hle/svc.cpp2
18 files changed, 242 insertions, 203 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ba24a6e02..bc3b429b3 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -45,6 +45,7 @@ set(SRCS
hle/kernel/client_port.cpp
hle/kernel/client_session.cpp
hle/kernel/event.cpp
+ hle/kernel/handle_table.cpp
hle/kernel/kernel.cpp
hle/kernel/memory.cpp
hle/kernel/mutex.cpp
@@ -237,6 +238,7 @@ set(HEADERS
hle/kernel/client_session.h
hle/kernel/errors.h
hle/kernel/event.h
+ hle/kernel/handle_table.h
hle/kernel/kernel.h
hle/kernel/memory.h
hle/kernel/mutex.h
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 06c4c5a85..d7348c09d 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -3,7 +3,9 @@
// Refer to the license.txt file included.
#pragma once
+
#include "core/hle/ipc.h"
+#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
namespace IPC {
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 6a7af93a9..1d24401b1 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
// Address arbiters are an underlying kernel synchronization object that can be created/used via
// supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 511490c7c..8f7d6ac44 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -7,6 +7,7 @@
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 9f3adb72b..2de379c09 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -6,10 +6,9 @@
#include <memory>
#include <string>
-
#include "common/common_types.h"
-
#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
new file mode 100644
index 000000000..c7322d883
--- /dev/null
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -0,0 +1,97 @@
+// 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/hle/kernel/errors.h"
+#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+HandleTable g_handle_table;
+
+HandleTable::HandleTable() {
+ next_generation = 1;
+ Clear();
+}
+
+ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
+ DEBUG_ASSERT(obj != nullptr);
+
+ u16 slot = next_free_slot;
+ if (slot >= generations.size()) {
+ LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
+ return ERR_OUT_OF_HANDLES;
+ }
+ next_free_slot = generations[slot];
+
+ u16 generation = next_generation++;
+
+ // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
+ // CTR-OS doesn't use generation 0, so skip straight to 1.
+ if (next_generation >= (1 << 15))
+ next_generation = 1;
+
+ generations[slot] = generation;
+ objects[slot] = std::move(obj);
+
+ Handle handle = generation | (slot << 15);
+ return MakeResult<Handle>(handle);
+}
+
+ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
+ SharedPtr<Object> object = GetGeneric(handle);
+ if (object == nullptr) {
+ LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
+ return ERR_INVALID_HANDLE;
+ }
+ return Create(std::move(object));
+}
+
+ResultCode HandleTable::Close(Handle handle) {
+ if (!IsValid(handle))
+ return ERR_INVALID_HANDLE;
+
+ u16 slot = GetSlot(handle);
+
+ objects[slot] = nullptr;
+
+ generations[slot] = next_free_slot;
+ next_free_slot = slot;
+ return RESULT_SUCCESS;
+}
+
+bool HandleTable::IsValid(Handle handle) const {
+ size_t slot = GetSlot(handle);
+ u16 generation = GetGeneration(handle);
+
+ return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
+}
+
+SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
+ if (handle == CurrentThread) {
+ return GetCurrentThread();
+ } else if (handle == CurrentProcess) {
+ return g_current_process;
+ }
+
+ if (!IsValid(handle)) {
+ return nullptr;
+ }
+ return objects[GetSlot(handle)];
+}
+
+void HandleTable::Clear() {
+ for (u16 i = 0; i < MAX_COUNT; ++i) {
+ generations[i] = i + 1;
+ objects[i] = nullptr;
+ }
+ next_free_slot = 0;
+}
+
+} // namespace
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
new file mode 100644
index 000000000..d6aaefbf7
--- /dev/null
+++ b/src/core/hle/kernel/handle_table.h
@@ -0,0 +1,126 @@
+// 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 "common/common_types.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+enum KernelHandle : Handle {
+ 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:
+ HandleTable();
+
+ /**
+ * Allocates a handle for the given object.
+ * @return The created Handle or one of the following errors:
+ * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
+ */
+ ResultVal<Handle> Create(SharedPtr<Object> obj);
+
+ /**
+ * 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.
+ */
+ ResultCode Close(Handle handle);
+
+ /// Checks if a handle is valid and points to an existing object.
+ bool IsValid(Handle handle) const;
+
+ /**
+ * Looks up a handle.
+ * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
+ */
+ SharedPtr<Object> GetGeneric(Handle handle) const;
+
+ /**
+ * Looks up a handle while verifying its type.
+ * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
+ * type differs from the requested one.
+ */
+ template <class T>
+ SharedPtr<T> Get(Handle handle) const {
+ return DynamicObjectCast<T>(GetGeneric(handle));
+ }
+
+ /// Closes all handles held in this table.
+ void Clear();
+
+private:
+ /**
+ * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
+ * reduced by ExHeader values, but this is not emulated here.
+ */
+ static const size_t MAX_COUNT = 4096;
+
+ static u16 GetSlot(Handle handle) {
+ return handle >> 15;
+ }
+ static u16 GetGeneration(Handle handle) {
+ return handle & 0x7FFF;
+ }
+
+ /// Stores the Object referenced by the handle or null if the slot is empty.
+ std::array<SharedPtr<Object>, 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;
+
+ /**
+ * 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;
+
+ /// Head of the free slots linked list.
+ u16 next_free_slot;
+};
+
+extern HandleTable g_handle_table;
+
+} // namespace
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b0af5b9b8..7470a97ca 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -2,11 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <algorithm>
-#include "common/assert.h"
-#include "common/logging/log.h"
#include "core/hle/config_mem.h"
-#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h"
@@ -18,86 +15,6 @@
namespace Kernel {
unsigned int Object::next_object_id;
-HandleTable g_handle_table;
-
-HandleTable::HandleTable() {
- next_generation = 1;
- Clear();
-}
-
-ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
- DEBUG_ASSERT(obj != nullptr);
-
- u16 slot = next_free_slot;
- if (slot >= generations.size()) {
- LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
- return ERR_OUT_OF_HANDLES;
- }
- next_free_slot = generations[slot];
-
- u16 generation = next_generation++;
-
- // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
- // CTR-OS doesn't use generation 0, so skip straight to 1.
- if (next_generation >= (1 << 15))
- next_generation = 1;
-
- generations[slot] = generation;
- objects[slot] = std::move(obj);
-
- Handle handle = generation | (slot << 15);
- return MakeResult<Handle>(handle);
-}
-
-ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
- SharedPtr<Object> object = GetGeneric(handle);
- if (object == nullptr) {
- LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
- return ERR_INVALID_HANDLE;
- }
- return Create(std::move(object));
-}
-
-ResultCode HandleTable::Close(Handle handle) {
- if (!IsValid(handle))
- return ERR_INVALID_HANDLE;
-
- u16 slot = GetSlot(handle);
-
- objects[slot] = nullptr;
-
- generations[slot] = next_free_slot;
- next_free_slot = slot;
- return RESULT_SUCCESS;
-}
-
-bool HandleTable::IsValid(Handle handle) const {
- size_t slot = GetSlot(handle);
- u16 generation = GetGeneration(handle);
-
- return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
-}
-
-SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
- if (handle == CurrentThread) {
- return GetCurrentThread();
- } else if (handle == CurrentProcess) {
- return g_current_process;
- }
-
- if (!IsValid(handle)) {
- return nullptr;
- }
- return objects[GetSlot(handle)];
-}
-
-void HandleTable::Clear() {
- for (u16 i = 0; i < MAX_COUNT; ++i) {
- generations[i] = i + 1;
- objects[i] = nullptr;
- }
- next_free_slot = 0;
-}
/// Initialize the kernel
void Init(u32 system_mode) {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 5335a961d..9cf288b08 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,24 +4,16 @@
#pragma once
-#include <algorithm>
-#include <array>
#include <cstddef>
#include <string>
-#include <vector>
+#include <utility>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include "common/common_types.h"
-#include "core/hle/result.h"
namespace Kernel {
using Handle = u32;
-enum KernelHandle : Handle {
- CurrentThread = 0xFFFF8000,
- CurrentProcess = 0xFFFF8001,
-};
-
enum class HandleType : u32 {
Unknown,
Event,
@@ -131,112 +123,6 @@ inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
return nullptr;
}
-/**
- * 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:
- HandleTable();
-
- /**
- * Allocates a handle for the given object.
- * @return The created Handle or one of the following errors:
- * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
- */
- ResultVal<Handle> Create(SharedPtr<Object> obj);
-
- /**
- * 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.
- */
- ResultCode Close(Handle handle);
-
- /// Checks if a handle is valid and points to an existing object.
- bool IsValid(Handle handle) const;
-
- /**
- * Looks up a handle.
- * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
- */
- SharedPtr<Object> GetGeneric(Handle handle) const;
-
- /**
- * Looks up a handle while verifying its type.
- * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
- * type differs from the requested one.
- */
- template <class T>
- SharedPtr<T> Get(Handle handle) const {
- return DynamicObjectCast<T>(GetGeneric(handle));
- }
-
- /// Closes all handles held in this table.
- void Clear();
-
-private:
- /**
- * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
- * reduced by ExHeader values, but this is not emulated here.
- */
- static const size_t MAX_COUNT = 4096;
-
- static u16 GetSlot(Handle handle) {
- return handle >> 15;
- }
- static u16 GetGeneration(Handle handle) {
- return handle & 0x7FFF;
- }
-
- /// Stores the Object referenced by the handle or null if the slot is empty.
- std::array<SharedPtr<Object>, 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;
-
- /**
- * 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;
-
- /// Head of the free slots linked list.
- u16 next_free_slot;
-};
-
-extern HandleTable g_handle_table;
-
/// Initialize the kernel with the specified system mode.
void Init(u32 system_mode);
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index 8250a90b5..804f23b1c 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <cinttypes>
#include <map>
#include <memory>
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 3f51bc5de..a8f10a3ee 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <cstring>
+#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/resource_limit.h"
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index ca6f908aa..7b0cacf2e 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -9,6 +9,7 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/wait_object.h"
+#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 315b80d14..f1b76d8aa 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -10,7 +10,6 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/session.h"
-#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@@ -21,6 +20,7 @@ namespace Kernel {
class ClientSession;
class ClientPort;
class ServerSession;
+class Thread;
/**
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 519ff51a8..75ce626f8 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -15,6 +15,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index a00c75679..6f2cf3b02 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -6,6 +6,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core_timing.h"
+#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index e63b61450..ee80926d2 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -4,6 +4,8 @@
#pragma once
+#include <vector>
+#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/kernel/kernel.h"
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index e6a5f1417..ffabc24a4 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -12,7 +12,6 @@
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/thread.h"
#include "core/hle/result.h"
#include "core/memory.h"
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 83767677f..e68b9f16a 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <cinttypes>
#include <map>
#include "common/logging/log.h"
@@ -16,6 +17,7 @@
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process.h"