2014-12-16 21:38:14 -08:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
2014-11-19 00:49:13 -08:00
|
|
|
// Refer to the license.txt file included.
|
2014-05-09 19:11:18 -07:00
|
|
|
|
2014-12-03 16:55:45 -08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2014-05-09 19:11:18 -07:00
|
|
|
#include "common/common.h"
|
|
|
|
|
2014-05-13 18:57:12 -07:00
|
|
|
#include "core/core.h"
|
2014-05-09 19:11:18 -07:00
|
|
|
#include "core/hle/kernel/kernel.h"
|
|
|
|
#include "core/hle/kernel/thread.h"
|
|
|
|
|
2014-05-20 15:13:25 -07:00
|
|
|
namespace Kernel {
|
2014-05-09 19:11:18 -07:00
|
|
|
|
2014-06-01 18:42:50 -07:00
|
|
|
Handle g_main_thread = 0;
|
2014-12-13 15:16:13 -08:00
|
|
|
HandleTable g_handle_table;
|
2014-12-15 21:33:41 -08:00
|
|
|
u64 g_program_id = 0;
|
2014-05-09 19:11:18 -07:00
|
|
|
|
2014-12-13 15:16:13 -08:00
|
|
|
HandleTable::HandleTable() {
|
2014-12-21 04:04:08 -08:00
|
|
|
next_generation = 1;
|
|
|
|
Clear();
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
ResultVal<Handle> HandleTable::Create(Object* obj) {
|
|
|
|
_dbg_assert_(Kernel, 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;
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
2014-12-21 04:04:08 -08:00
|
|
|
next_free_slot = generations[slot];
|
2014-05-09 19:11:18 -07:00
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
u16 generation = next_generation++;
|
2014-05-09 19:11:18 -07:00
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
// 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;
|
|
|
|
intrusive_ptr_add_ref(obj);
|
|
|
|
objects[slot] = obj;
|
|
|
|
|
|
|
|
Handle handle = generation | (slot << 15);
|
|
|
|
obj->handle = handle;
|
|
|
|
return MakeResult<Handle>(handle);
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
|
|
|
|
Object* object = GetGeneric(handle);
|
|
|
|
if (object == nullptr) {
|
|
|
|
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
|
|
|
|
return ERR_INVALID_HANDLE;
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
2014-12-21 04:04:08 -08:00
|
|
|
return Create(object);
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
ResultCode HandleTable::Close(Handle handle) {
|
|
|
|
if (!IsValid(handle))
|
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
|
|
|
|
|
size_t slot = GetSlot(handle);
|
|
|
|
u16 generation = GetGeneration(handle);
|
|
|
|
|
|
|
|
intrusive_ptr_release(objects[slot]);
|
|
|
|
objects[slot] = nullptr;
|
|
|
|
|
|
|
|
generations[generation] = next_free_slot;
|
|
|
|
next_free_slot = slot;
|
|
|
|
return RESULT_SUCCESS;
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
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;
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
Object* HandleTable::GetGeneric(Handle handle) const {
|
|
|
|
if (handle == CurrentThread) {
|
|
|
|
// TODO(yuriks) Directly return the pointer once this is possible.
|
|
|
|
handle = GetCurrentThreadHandle();
|
|
|
|
} else if (handle == CurrentProcess) {
|
|
|
|
LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsValid(handle)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return objects[GetSlot(handle)];
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
|
|
|
|
2014-12-21 04:04:08 -08:00
|
|
|
void HandleTable::Clear() {
|
|
|
|
for (size_t i = 0; i < MAX_COUNT; ++i) {
|
|
|
|
generations[i] = i + 1;
|
|
|
|
if (objects[i] != nullptr)
|
|
|
|
intrusive_ptr_release(objects[i]);
|
|
|
|
objects[i] = nullptr;
|
|
|
|
}
|
|
|
|
next_free_slot = 0;
|
2014-05-09 19:11:18 -07:00
|
|
|
}
|
2014-05-13 18:57:12 -07:00
|
|
|
|
2014-06-10 19:43:50 -07:00
|
|
|
/// Initialize the kernel
|
2014-05-20 15:13:25 -07:00
|
|
|
void Init() {
|
2014-05-20 16:37:46 -07:00
|
|
|
Kernel::ThreadingInit();
|
2014-05-20 15:13:25 -07:00
|
|
|
}
|
|
|
|
|
2014-06-10 19:43:50 -07:00
|
|
|
/// Shutdown the kernel
|
2014-05-20 15:13:25 -07:00
|
|
|
void Shutdown() {
|
2014-05-20 16:37:46 -07:00
|
|
|
Kernel::ThreadingShutdown();
|
2014-06-10 19:43:50 -07:00
|
|
|
|
2014-12-13 15:16:13 -08:00
|
|
|
g_handle_table.Clear(); // Free all kernel objects
|
2014-05-20 15:13:25 -07:00
|
|
|
}
|
|
|
|
|
2014-05-22 16:06:12 -07:00
|
|
|
/**
|
|
|
|
* Loads executable stored at specified address
|
|
|
|
* @entry_point Entry point in memory of loaded executable
|
|
|
|
* @return True on success, otherwise false
|
|
|
|
*/
|
|
|
|
bool LoadExec(u32 entry_point) {
|
2014-05-13 18:57:12 -07:00
|
|
|
Core::g_app_core->SetPC(entry_point);
|
|
|
|
|
2014-05-14 17:49:27 -07:00
|
|
|
// 0x30 is the typical main thread priority I've seen used so far
|
2014-06-04 21:20:58 -07:00
|
|
|
g_main_thread = Kernel::SetupMainThread(0x30);
|
2015-01-07 07:10:58 -08:00
|
|
|
// Setup the idle thread
|
|
|
|
Kernel::SetupIdleThread();
|
2014-05-13 18:57:12 -07:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2014-05-22 16:06:12 -07:00
|
|
|
|
|
|
|
} // namespace
|