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