18 changed files with 242 additions and 203 deletions
-
2src/core/CMakeLists.txt
-
2src/core/hle/ipc_helpers.h
-
1src/core/hle/kernel/address_arbiter.h
-
1src/core/hle/kernel/client_port.h
-
3src/core/hle/kernel/client_session.h
-
97src/core/hle/kernel/handle_table.cpp
-
126src/core/hle/kernel/handle_table.h
-
85src/core/hle/kernel/kernel.cpp
-
116src/core/hle/kernel/kernel.h
-
1src/core/hle/kernel/memory.cpp
-
1src/core/hle/kernel/resource_limit.cpp
-
1src/core/hle/kernel/semaphore.h
-
2src/core/hle/kernel/server_session.h
-
1src/core/hle/kernel/thread.cpp
-
1src/core/hle/kernel/timer.cpp
-
2src/core/hle/service/apt/apt.h
-
1src/core/hle/service/service.h
-
2src/core/hle/svc.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
|
|||
@ -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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue