summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/kernel.h
blob: 00f9b57fc2f28738b3c6f5e8bf3d5d21bb1b8b37 (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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2014 Citra Emulator Project / PPSSPP Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <string>
#include "common/common.h"
#include "core/hle/result.h"

typedef u32 Handle;
typedef s32 Result;

namespace Kernel {

enum KernelHandle {
    CurrentThread   = 0xFFFF8000,
    CurrentProcess  = 0xFFFF8001,
};

enum class HandleType : u32 {
    Unknown         = 0,
    Port            = 1,
    Service         = 2,
    Event           = 3,
    Mutex           = 4,
    SharedMemory    = 5,
    Redirection     = 6,
    Thread          = 7,
    Process         = 8,
    AddressArbiter  = 9,
    File            = 10,
    Semaphore       = 11,
    Archive         = 12,
    Directory       = 13,
};

enum {
    DEFAULT_STACK_SIZE  = 0x4000,
};

class ObjectPool;

class Object : NonCopyable {
    friend class ObjectPool;
    u32 handle;
public:
    virtual ~Object() {}
    Handle GetHandle() const { return handle; }
    virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
    virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
    virtual Kernel::HandleType GetHandleType() const = 0;

    /**
     * Synchronize kernel object.
     * @return True if the current thread should wait as a result of the sync
     */
    virtual ResultVal<bool> SyncRequest() {
        LOG_ERROR(Kernel, "(UNIMPLEMENTED)");
        return UnimplementedFunction(ErrorModule::Kernel);
    }

    /**
     * Wait for kernel object to synchronize.
     * @return True if the current thread should wait as a result of the wait
     */
    virtual ResultVal<bool> WaitSynchronization() {
        LOG_ERROR(Kernel, "(UNIMPLEMENTED)");
        return UnimplementedFunction(ErrorModule::Kernel);
    }
};

class ObjectPool : NonCopyable {
public:
    ObjectPool();
    ~ObjectPool() {}

    // Allocates a handle within the range and inserts the object into the map.
    Handle Create(Object* obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF);

    static Object* CreateByIDType(int type);

    template <class T>
    void Destroy(Handle handle) {
        if (Get<T>(handle)) {
            occupied[handle - HANDLE_OFFSET] = false;
            delete pool[handle - HANDLE_OFFSET];
        }
    }

    bool IsValid(Handle handle) const;

    template <class T>
    T* Get(Handle handle) {
        if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
            if (handle != 0) {
                LOG_ERROR(Kernel, "Bad object handle %08x", handle, handle);
            }
            return nullptr;
        } else {
            Object* t = pool[handle - HANDLE_OFFSET];
            if (t->GetHandleType() != T::GetStaticHandleType()) {
                LOG_ERROR(Kernel, "Wrong object type for %08x", handle, handle);
                return nullptr;
            }
            return static_cast<T*>(t);
        }
    }

    // ONLY use this when you know the handle is valid.
    template <class T>
    T *GetFast(Handle handle) {
        const Handle realHandle = handle - HANDLE_OFFSET;
        _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]);
        return static_cast<T*>(pool[realHandle]);
    }

    template <class T, typename ArgT>
    void Iterate(bool func(T*, ArgT), ArgT arg) {
        int type = T::GetStaticIDType();
        for (int i = 0; i < MAX_COUNT; i++)
        {
            if (!occupied[i])
                continue;
            T* t = static_cast<T*>(pool[i]);
            if (t->GetIDType() == type) {
                if (!func(t, arg))
                    break;
            }
        }
    }

    bool GetIDType(Handle handle, HandleType* type) const {
        if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) ||
                !occupied[handle - HANDLE_OFFSET]) {
            LOG_ERROR(Kernel, "Bad object handle %08X", handle, handle);
            return false;
        }
        Object* t = pool[handle - HANDLE_OFFSET];
        *type = t->GetHandleType();
        return true;
    }

    Object* &operator [](Handle handle);
    void List();
    void Clear();
    int GetCount() const;

private:

    enum {
        MAX_COUNT       = 0x1000,
        HANDLE_OFFSET   = 0x100,
        INITIAL_NEXT_ID = 0x10,
    };

    std::array<Object*, MAX_COUNT> pool;
    std::array<bool, MAX_COUNT> occupied;
    int next_id;
};

extern ObjectPool g_object_pool;
extern Handle g_main_thread;

/// Initialize the kernel
void Init();

/// Shutdown the kernel
void Shutdown();

/**
 * 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);

} // namespace