summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/kernel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
-rw-r--r--src/core/hle/kernel/kernel.cpp283
1 files changed, 268 insertions, 15 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 8c19e86d3..615d7901a 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -2,38 +2,291 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
6#include <atomic>
7#include <memory>
8#include <mutex>
9#include <utility>
10
11#include "common/assert.h"
12#include "common/logging/log.h"
13
14#include "core/core.h"
15#include "core/core_timing.h"
5#include "core/hle/kernel/handle_table.h" 16#include "core/hle/kernel/handle_table.h"
6#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
7#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
8#include "core/hle/kernel/resource_limit.h" 19#include "core/hle/kernel/resource_limit.h"
9#include "core/hle/kernel/thread.h" 20#include "core/hle/kernel/thread.h"
10#include "core/hle/kernel/timer.h" 21#include "core/hle/kernel/timer.h"
22#include "core/hle/lock.h"
23#include "core/hle/result.h"
11 24
12namespace Kernel { 25namespace Kernel {
13 26
14std::atomic<u32> Object::next_object_id{0}; 27/**
28 * Callback that will wake up the thread it was scheduled for
29 * @param thread_handle The handle of the thread that's been awoken
30 * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
31 */
32static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) {
33 const auto proper_handle = static_cast<Handle>(thread_handle);
34 auto& system = Core::System::GetInstance();
35
36 // Lock the global kernel mutex when we enter the kernel HLE.
37 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
38
39 SharedPtr<Thread> thread =
40 system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle);
41 if (thread == nullptr) {
42 LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
43 return;
44 }
45
46 bool resume = true;
47
48 if (thread->status == ThreadStatus::WaitSynchAny ||
49 thread->status == ThreadStatus::WaitSynchAll ||
50 thread->status == ThreadStatus::WaitHLEEvent) {
51 // Remove the thread from each of its waiting objects' waitlists
52 for (auto& object : thread->wait_objects) {
53 object->RemoveWaitingThread(thread.get());
54 }
55 thread->wait_objects.clear();
56
57 // Invoke the wakeup callback before clearing the wait objects
58 if (thread->wakeup_callback) {
59 resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
60 }
61 }
62
63 if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
64 thread->wait_handle) {
65 ASSERT(thread->status == ThreadStatus::WaitMutex);
66 thread->mutex_wait_address = 0;
67 thread->condvar_wait_address = 0;
68 thread->wait_handle = 0;
69
70 auto lock_owner = thread->lock_owner;
71 // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
72 // and don't have a lock owner unless SignalProcessWideKey was called first and the thread
73 // wasn't awakened due to the mutex already being acquired.
74 if (lock_owner) {
75 lock_owner->RemoveMutexWaiter(thread);
76 }
77 }
78
79 if (thread->arb_wait_address != 0) {
80 ASSERT(thread->status == ThreadStatus::WaitArb);
81 thread->arb_wait_address = 0;
82 }
83
84 if (resume) {
85 thread->ResumeFromWait();
86 }
87}
88
89/// The timer callback event, called when a timer is fired
90static void TimerCallback(u64 timer_handle, int cycles_late) {
91 const auto proper_handle = static_cast<Handle>(timer_handle);
92 auto& system = Core::System::GetInstance();
93 SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle);
94
95 if (timer == nullptr) {
96 LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
97 return;
98 }
99
100 timer->Signal(cycles_late);
101}
15 102
16/// Initialize the kernel 103struct KernelCore::Impl {
17void Init() { 104 void Initialize(KernelCore& kernel) {
18 Kernel::ResourceLimitsInit(); 105 Shutdown();
19 Kernel::ThreadingInit();
20 Kernel::TimersInit();
21 106
22 Object::next_object_id = 0; 107 InitializeResourceLimits(kernel);
108 InitializeThreads();
109 InitializeTimers();
110 }
111
112 void Shutdown() {
113 next_object_id = 0;
114 next_process_id = 10;
115 next_thread_id = 1;
116
117 process_list.clear();
118
119 handle_table.Clear();
120 resource_limits.fill(nullptr);
121
122 thread_wakeup_callback_handle_table.Clear();
123 thread_wakeup_event_type = nullptr;
124
125 timer_callback_handle_table.Clear();
126 timer_callback_event_type = nullptr;
127 }
128
129 void InitializeResourceLimits(KernelCore& kernel) {
130 // Create the four resource limits that the system uses
131 // Create the APPLICATION resource limit
132 SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications");
133 resource_limit->max_priority = 0x18;
134 resource_limit->max_commit = 0x4000000;
135 resource_limit->max_threads = 0x20;
136 resource_limit->max_events = 0x20;
137 resource_limit->max_mutexes = 0x20;
138 resource_limit->max_semaphores = 0x8;
139 resource_limit->max_timers = 0x8;
140 resource_limit->max_shared_mems = 0x10;
141 resource_limit->max_address_arbiters = 0x2;
142 resource_limit->max_cpu_time = 0x1E;
143 resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
144
145 // Create the SYS_APPLET resource limit
146 resource_limit = ResourceLimit::Create(kernel, "System Applets");
147 resource_limit->max_priority = 0x4;
148 resource_limit->max_commit = 0x5E00000;
149 resource_limit->max_threads = 0x1D;
150 resource_limit->max_events = 0xB;
151 resource_limit->max_mutexes = 0x8;
152 resource_limit->max_semaphores = 0x4;
153 resource_limit->max_timers = 0x4;
154 resource_limit->max_shared_mems = 0x8;
155 resource_limit->max_address_arbiters = 0x3;
156 resource_limit->max_cpu_time = 0x2710;
157 resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
158
159 // Create the LIB_APPLET resource limit
160 resource_limit = ResourceLimit::Create(kernel, "Library Applets");
161 resource_limit->max_priority = 0x4;
162 resource_limit->max_commit = 0x600000;
163 resource_limit->max_threads = 0xE;
164 resource_limit->max_events = 0x8;
165 resource_limit->max_mutexes = 0x8;
166 resource_limit->max_semaphores = 0x4;
167 resource_limit->max_timers = 0x4;
168 resource_limit->max_shared_mems = 0x8;
169 resource_limit->max_address_arbiters = 0x1;
170 resource_limit->max_cpu_time = 0x2710;
171 resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
172
173 // Create the OTHER resource limit
174 resource_limit = ResourceLimit::Create(kernel, "Others");
175 resource_limit->max_priority = 0x4;
176 resource_limit->max_commit = 0x2180000;
177 resource_limit->max_threads = 0xE1;
178 resource_limit->max_events = 0x108;
179 resource_limit->max_mutexes = 0x25;
180 resource_limit->max_semaphores = 0x43;
181 resource_limit->max_timers = 0x2C;
182 resource_limit->max_shared_mems = 0x1F;
183 resource_limit->max_address_arbiters = 0x2D;
184 resource_limit->max_cpu_time = 0x3E8;
185 resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
186 }
187
188 void InitializeThreads() {
189 thread_wakeup_event_type =
190 CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
191 }
192
193 void InitializeTimers() {
194 timer_callback_handle_table.Clear();
195 timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
196 }
197
198 std::atomic<u32> next_object_id{0};
23 // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are 199 // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
24 // reserved for low-level services 200 // reserved for low-level services
25 Process::next_process_id = 10; 201 std::atomic<u32> next_process_id{10};
202 std::atomic<u32> next_thread_id{1};
203
204 // Lists all processes that exist in the current session.
205 std::vector<SharedPtr<Process>> process_list;
206
207 Kernel::HandleTable handle_table;
208 std::array<SharedPtr<ResourceLimit>, 4> resource_limits;
209
210 /// The event type of the generic timer callback event
211 CoreTiming::EventType* timer_callback_event_type = nullptr;
212 // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future,
213 // allowing us to simply use a pool index or similar.
214 Kernel::HandleTable timer_callback_handle_table;
215
216 CoreTiming::EventType* thread_wakeup_event_type = nullptr;
217 // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
218 // allowing us to simply use a pool index or similar.
219 Kernel::HandleTable thread_wakeup_callback_handle_table;
220};
221
222KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {}
223KernelCore::~KernelCore() {
224 Shutdown();
225}
226
227void KernelCore::Initialize() {
228 impl->Initialize(*this);
229}
230
231void KernelCore::Shutdown() {
232 impl->Shutdown();
233}
234
235Kernel::HandleTable& KernelCore::HandleTable() {
236 return impl->handle_table;
237}
238
239const Kernel::HandleTable& KernelCore::HandleTable() const {
240 return impl->handle_table;
241}
242
243SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory(
244 ResourceLimitCategory category) const {
245 return impl->resource_limits.at(static_cast<std::size_t>(category));
246}
247
248SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {
249 return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
250}
251
252SharedPtr<Timer> KernelCore::RetrieveTimerFromCallbackHandleTable(Handle handle) const {
253 return impl->timer_callback_handle_table.Get<Timer>(handle);
254}
255
256void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
257 impl->process_list.push_back(std::move(process));
258}
259
260u32 KernelCore::CreateNewObjectID() {
261 return impl->next_object_id++;
262}
263
264u32 KernelCore::CreateNewThreadID() {
265 return impl->next_thread_id++;
26} 266}
27 267
28/// Shutdown the kernel 268u32 KernelCore::CreateNewProcessID() {
29void Shutdown() { 269 return impl->next_process_id++;
30 // Free all kernel objects 270}
31 g_handle_table.Clear();
32 271
33 Kernel::ThreadingShutdown(); 272ResultVal<Handle> KernelCore::CreateTimerCallbackHandle(const SharedPtr<Timer>& timer) {
273 return impl->timer_callback_handle_table.Create(timer);
274}
275
276CoreTiming::EventType* KernelCore::ThreadWakeupCallbackEventType() const {
277 return impl->thread_wakeup_event_type;
278}
279
280CoreTiming::EventType* KernelCore::TimerCallbackEventType() const {
281 return impl->timer_callback_event_type;
282}
283
284Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() {
285 return impl->thread_wakeup_callback_handle_table;
286}
34 287
35 Kernel::TimersShutdown(); 288const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const {
36 Kernel::ResourceLimitsShutdown(); 289 return impl->thread_wakeup_callback_handle_table;
37} 290}
38 291
39} // namespace Kernel 292} // namespace Kernel