2014-05-10 03:11:18 +01:00
|
|
|
// Copyright 2014 Citra Emulator Project / PPSSPP Project
|
|
|
|
// Licensed under GPLv2
|
2014-11-19 08:49:13 +00:00
|
|
|
// Refer to the license.txt file included.
|
2014-05-10 03:11:18 +01:00
|
|
|
|
|
|
|
#include "common/common.h"
|
|
|
|
|
2014-05-14 02:57:12 +01:00
|
|
|
#include "core/core.h"
|
2014-05-10 03:11:18 +01:00
|
|
|
#include "core/hle/kernel/kernel.h"
|
|
|
|
#include "core/hle/kernel/thread.h"
|
2014-07-04 18:38:12 +01:00
|
|
|
#include "core/hle/kernel/archive.h"
|
2014-05-10 03:11:18 +01:00
|
|
|
|
2014-05-20 23:13:25 +01:00
|
|
|
namespace Kernel {
|
2014-05-10 03:11:18 +01:00
|
|
|
|
2014-06-02 02:42:50 +01:00
|
|
|
Handle g_main_thread = 0;
|
2014-05-20 23:13:25 +01:00
|
|
|
ObjectPool g_object_pool;
|
2014-05-10 03:11:18 +01:00
|
|
|
|
2014-05-20 23:13:25 +01:00
|
|
|
ObjectPool::ObjectPool() {
|
2014-05-10 03:11:18 +01:00
|
|
|
next_id = INITIAL_NEXT_ID;
|
|
|
|
}
|
|
|
|
|
2014-05-20 23:13:25 +01:00
|
|
|
Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) {
|
2014-05-10 03:11:18 +01:00
|
|
|
if (range_top > MAX_COUNT) {
|
|
|
|
range_top = MAX_COUNT;
|
|
|
|
}
|
|
|
|
if (next_id >= range_bottom && next_id < range_top) {
|
|
|
|
range_bottom = next_id++;
|
|
|
|
}
|
|
|
|
for (int i = range_bottom; i < range_top; i++) {
|
|
|
|
if (!occupied[i]) {
|
|
|
|
occupied[i] = true;
|
|
|
|
pool[i] = obj;
|
2014-05-15 23:26:28 +01:00
|
|
|
pool[i]->handle = i + HANDLE_OFFSET;
|
2014-05-10 03:11:18 +01:00
|
|
|
return i + HANDLE_OFFSET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-04 00:48:34 +00:00
|
|
|
bool ObjectPool::IsValid(Handle handle) const {
|
2014-05-10 03:11:18 +01:00
|
|
|
int index = handle - HANDLE_OFFSET;
|
|
|
|
if (index < 0)
|
|
|
|
return false;
|
|
|
|
if (index >= MAX_COUNT)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return occupied[index];
|
|
|
|
}
|
|
|
|
|
2014-05-20 23:13:25 +01:00
|
|
|
void ObjectPool::Clear() {
|
|
|
|
for (int i = 0; i < MAX_COUNT; i++) {
|
2014-05-10 03:11:18 +01:00
|
|
|
//brutally clear everything, no validation
|
|
|
|
if (occupied[i])
|
|
|
|
delete pool[i];
|
|
|
|
occupied[i] = false;
|
|
|
|
}
|
2014-08-19 05:20:56 +01:00
|
|
|
pool.fill(nullptr);
|
2014-05-10 03:11:18 +01:00
|
|
|
next_id = INITIAL_NEXT_ID;
|
|
|
|
}
|
|
|
|
|
2014-05-20 23:13:25 +01:00
|
|
|
Object* &ObjectPool::operator [](Handle handle)
|
2014-05-10 03:11:18 +01:00
|
|
|
{
|
|
|
|
_dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
|
|
|
|
return pool[handle - HANDLE_OFFSET];
|
|
|
|
}
|
|
|
|
|
2014-05-20 23:13:25 +01:00
|
|
|
void ObjectPool::List() {
|
2014-05-10 03:11:18 +01:00
|
|
|
for (int i = 0; i < MAX_COUNT; i++) {
|
|
|
|
if (occupied[i]) {
|
|
|
|
if (pool[i]) {
|
2014-11-19 08:49:13 +00:00
|
|
|
INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(),
|
2014-08-18 04:03:22 +01:00
|
|
|
pool[i]->GetName().c_str());
|
2014-05-10 03:11:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-04 00:48:34 +00:00
|
|
|
int ObjectPool::GetCount() const {
|
2014-05-10 03:11:18 +01:00
|
|
|
int count = 0;
|
2014-05-20 23:13:25 +01:00
|
|
|
for (int i = 0; i < MAX_COUNT; i++) {
|
2014-05-10 03:11:18 +01:00
|
|
|
if (occupied[i])
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-05-20 23:13:25 +01:00
|
|
|
Object* ObjectPool::CreateByIDType(int type) {
|
2014-09-14 03:48:30 +01:00
|
|
|
ERROR_LOG(COMMON, "Unimplemented: %d.", type);
|
|
|
|
return nullptr;
|
2014-05-10 03:11:18 +01:00
|
|
|
}
|
2014-05-14 02:57:12 +01:00
|
|
|
|
2014-06-11 03:43:50 +01:00
|
|
|
/// Initialize the kernel
|
2014-05-20 23:13:25 +01:00
|
|
|
void Init() {
|
2014-05-21 00:37:46 +01:00
|
|
|
Kernel::ThreadingInit();
|
2014-07-04 18:38:12 +01:00
|
|
|
Kernel::ArchiveInit();
|
2014-05-20 23:13:25 +01:00
|
|
|
}
|
|
|
|
|
2014-06-11 03:43:50 +01:00
|
|
|
/// Shutdown the kernel
|
2014-05-20 23:13:25 +01:00
|
|
|
void Shutdown() {
|
2014-05-21 00:37:46 +01:00
|
|
|
Kernel::ThreadingShutdown();
|
2014-07-04 18:38:12 +01:00
|
|
|
Kernel::ArchiveShutdown();
|
2014-06-11 03:43:50 +01:00
|
|
|
|
|
|
|
g_object_pool.Clear(); // Free all kernel objects
|
2014-05-20 23:13:25 +01:00
|
|
|
}
|
|
|
|
|
2014-05-23 00:06:12 +01: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) {
|
|
|
|
Init();
|
2014-11-19 08:49:13 +00:00
|
|
|
|
2014-05-14 02:57:12 +01:00
|
|
|
Core::g_app_core->SetPC(entry_point);
|
|
|
|
|
2014-05-15 01:49:27 +01:00
|
|
|
// 0x30 is the typical main thread priority I've seen used so far
|
2014-06-05 05:20:58 +01:00
|
|
|
g_main_thread = Kernel::SetupMainThread(0x30);
|
2014-05-14 02:57:12 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2014-05-23 00:06:12 +01:00
|
|
|
|
|
|
|
} // namespace
|