summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/kernel.cpp
blob: a4a2588756851ca4d3d142fc85f33c6275e00275 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2014 Citra Emulator Project / PPSSPP Project
// Licensed under GPLv2
// Refer to the license.txt file included.  

#include <string.h>

#include "common/common.h"

#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/archive.h"

namespace Kernel {

Handle g_main_thread = 0;
ObjectPool g_object_pool;

ObjectPool::ObjectPool() {
    next_id = INITIAL_NEXT_ID;
}

Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) {
    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;
            pool[i]->handle = i + HANDLE_OFFSET;
            return i + HANDLE_OFFSET;
        }
    }
    ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use.");
    return 0;
}

bool ObjectPool::IsValid(Handle handle) {
    int index = handle - HANDLE_OFFSET;
    if (index < 0)
        return false;
    if (index >= MAX_COUNT)
        return false;

    return occupied[index];
}

void ObjectPool::Clear() {
    for (int i = 0; i < MAX_COUNT; i++) {
        //brutally clear everything, no validation
        if (occupied[i])
            delete pool[i];
        occupied[i] = false;
    }
    pool.fill(nullptr);
    next_id = INITIAL_NEXT_ID;
}

Object* &ObjectPool::operator [](Handle handle)
{
    _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
    return pool[handle - HANDLE_OFFSET];
}

void ObjectPool::List() {
    for (int i = 0; i < MAX_COUNT; i++) {
        if (occupied[i]) {
            if (pool[i]) {
                INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(), 
                    pool[i]->GetName().c_str());
            }
        }
    }
}

int ObjectPool::GetCount() {
    int count = 0;
    for (int i = 0; i < MAX_COUNT; i++) {
        if (occupied[i])
            count++;
    }
    return count;
}

Object* ObjectPool::CreateByIDType(int type) {
    // Used for save states.  This is ugly, but what other way is there?
    switch (type) {
    //case SCE_KERNEL_TMID_Alarm:
    //    return __KernelAlarmObject();
    //case SCE_KERNEL_TMID_EventFlag:
    //    return __KernelEventFlagObject();
    //case SCE_KERNEL_TMID_Mbox:
    //    return __KernelMbxObject();
    //case SCE_KERNEL_TMID_Fpl:
    //    return __KernelMemoryFPLObject();
    //case SCE_KERNEL_TMID_Vpl:
    //    return __KernelMemoryVPLObject();
    //case PPSSPP_KERNEL_TMID_PMB:
    //    return __KernelMemoryPMBObject();
    //case PPSSPP_KERNEL_TMID_Module:
    //    return __KernelModuleObject();
    //case SCE_KERNEL_TMID_Mpipe:
    //    return __KernelMsgPipeObject();
    //case SCE_KERNEL_TMID_Mutex:
    //    return __KernelMutexObject();
    //case SCE_KERNEL_TMID_LwMutex:
    //    return __KernelLwMutexObject();
    //case SCE_KERNEL_TMID_Semaphore:
    //    return __KernelSemaphoreObject();
    //case SCE_KERNEL_TMID_Callback:
    //    return __KernelCallbackObject();
    //case SCE_KERNEL_TMID_Thread:
    //    return __KernelThreadObject();
    //case SCE_KERNEL_TMID_VTimer:
    //    return __KernelVTimerObject();
    //case SCE_KERNEL_TMID_Tlspl:
    //    return __KernelTlsplObject();
    //case PPSSPP_KERNEL_TMID_File:
    //    return __KernelFileNodeObject();
    //case PPSSPP_KERNEL_TMID_DirList:
    //    return __KernelDirListingObject();

    default:
        ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
        return nullptr;
    }
}

/// Initialize the kernel
void Init() {
    Kernel::ThreadingInit();
    Kernel::ArchiveInit();
}

/// Shutdown the kernel
void Shutdown() {
    Kernel::ThreadingShutdown();
    Kernel::ArchiveShutdown();

    g_object_pool.Clear(); // Free all kernel objects
}

/**
 * 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();
    
    Core::g_app_core->SetPC(entry_point);

    // 0x30 is the typical main thread priority I've seen used so far
    g_main_thread = Kernel::SetupMainThread(0x30);

    return true;
}

} // namespace