1 // Copyright 2014 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <array>
6 #include <atomic>
7 #include <bitset>
8 #include <functional>
9 #include <memory>
10 #include <thread>
11 #include <unordered_map>
12 #include <utility>
13
14 #include "common/assert.h"
15 #include "common/logging/log.h"
16 #include "common/microprofile.h"
17 #include "common/thread.h"
18 #include "core/arm/arm_interface.h"
19 #include "core/arm/cpu_interrupt_handler.h"
20 #include "core/arm/exclusive_monitor.h"
21 #include "core/core.h"
22 #include "core/core_timing.h"
23 #include "core/core_timing_util.h"
24 #include "core/cpu_manager.h"
25 #include "core/device_memory.h"
26 #include "core/hardware_properties.h"
27 #include "core/hle/kernel/client_port.h"
28 #include "core/hle/kernel/errors.h"
29 #include "core/hle/kernel/handle_table.h"
30 #include "core/hle/kernel/kernel.h"
31 #include "core/hle/kernel/memory/memory_layout.h"
32 #include "core/hle/kernel/memory/memory_manager.h"
33 #include "core/hle/kernel/memory/slab_heap.h"
34 #include "core/hle/kernel/physical_core.h"
35 #include "core/hle/kernel/process.h"
36 #include "core/hle/kernel/resource_limit.h"
37 #include "core/hle/kernel/scheduler.h"
38 #include "core/hle/kernel/shared_memory.h"
39 #include "core/hle/kernel/synchronization.h"
40 #include "core/hle/kernel/thread.h"
41 #include "core/hle/kernel/time_manager.h"
42 #include "core/hle/lock.h"
43 #include "core/hle/result.h"
44 #include "core/memory.h"
45
46 MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
47
48 namespace Kernel {
49
50 struct KernelCore::Impl {
ImplKernel::KernelCore::Impl51 explicit Impl(Core::System& system, KernelCore& kernel)
52 : global_scheduler{kernel}, synchronization{system}, time_manager{system},
53 global_handle_table{kernel}, system{system} {}
54
SetMulticoreKernel::KernelCore::Impl55 void SetMulticore(bool is_multicore) {
56 this->is_multicore = is_multicore;
57 }
58
InitializeKernel::KernelCore::Impl59 void Initialize(KernelCore& kernel) {
60 Shutdown();
61 RegisterHostThread();
62
63 InitializePhysicalCores();
64 InitializeSystemResourceLimit(kernel);
65 InitializeMemoryLayout();
66 InitializePreemption(kernel);
67 InitializeSchedulers();
68 InitializeSuspendThreads();
69 }
70
InitializeCoresKernel::KernelCore::Impl71 void InitializeCores() {
72 for (auto& core : cores) {
73 core.Initialize(current_process->Is64BitProcess());
74 }
75 }
76
ShutdownKernel::KernelCore::Impl77 void Shutdown() {
78 next_object_id = 0;
79 next_kernel_process_id = Process::InitialKIPIDMin;
80 next_user_process_id = Process::ProcessIDMin;
81 next_thread_id = 1;
82
83 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
84 if (suspend_threads[i]) {
85 suspend_threads[i].reset();
86 }
87 }
88
89 for (std::size_t i = 0; i < cores.size(); i++) {
90 cores[i].Shutdown();
91 schedulers[i].reset();
92 }
93 cores.clear();
94
95 process_list.clear();
96 current_process = nullptr;
97
98 system_resource_limit = nullptr;
99
100 global_handle_table.Clear();
101 preemption_event = nullptr;
102
103 global_scheduler.Shutdown();
104
105 named_ports.clear();
106
107 for (auto& core : cores) {
108 core.Shutdown();
109 }
110 cores.clear();
111
112 exclusive_monitor.reset();
113
114 num_host_threads = 0;
115 std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
116 std::thread::id{});
117 std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
118 }
119
InitializePhysicalCoresKernel::KernelCore::Impl120 void InitializePhysicalCores() {
121 exclusive_monitor =
122 Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
123 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
124 schedulers[i] = std::make_unique<Kernel::Scheduler>(system, i);
125 cores.emplace_back(i, system, *schedulers[i], interrupts);
126 }
127 }
128
InitializeSchedulersKernel::KernelCore::Impl129 void InitializeSchedulers() {
130 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
131 cores[i].Scheduler().Initialize();
132 }
133 }
134
135 // Creates the default system resource limit
InitializeSystemResourceLimitKernel::KernelCore::Impl136 void InitializeSystemResourceLimit(KernelCore& kernel) {
137 system_resource_limit = ResourceLimit::Create(kernel);
138
139 // If setting the default system values fails, then something seriously wrong has occurred.
140 ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x100000000)
141 .IsSuccess());
142 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
143 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
144 ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
145 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
146
147 if (!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0) ||
148 !system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0x60000)) {
149 UNREACHABLE();
150 }
151 }
152
InitializePreemptionKernel::KernelCore::Impl153 void InitializePreemption(KernelCore& kernel) {
154 preemption_event = Core::Timing::CreateEvent(
155 "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) {
156 {
157 SchedulerLock lock(kernel);
158 global_scheduler.PreemptThreads();
159 }
160 const auto time_interval = std::chrono::nanoseconds{
161 Core::Timing::msToCycles(std::chrono::milliseconds(10))};
162 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
163 });
164
165 const auto time_interval =
166 std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))};
167 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
168 }
169
InitializeSuspendThreadsKernel::KernelCore::Impl170 void InitializeSuspendThreads() {
171 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
172 std::string name = "Suspend Thread Id:" + std::to_string(i);
173 std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
174 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
175 const auto type =
176 static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND);
177 auto thread_res =
178 Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
179 nullptr, std::move(init_func), init_func_parameter);
180
181 suspend_threads[i] = std::move(thread_res).Unwrap();
182 }
183 }
184
MakeCurrentProcessKernel::KernelCore::Impl185 void MakeCurrentProcess(Process* process) {
186 current_process = process;
187 if (process == nullptr) {
188 return;
189 }
190
191 const u32 core_id = GetCurrentHostThreadID();
192 if (core_id < Core::Hardware::NUM_CPU_CORES) {
193 system.Memory().SetCurrentPageTable(*process, core_id);
194 }
195 }
196
RegisterCoreThreadKernel::KernelCore::Impl197 void RegisterCoreThread(std::size_t core_id) {
198 const std::thread::id this_id = std::this_thread::get_id();
199 if (!is_multicore) {
200 single_core_thread_id = this_id;
201 }
202 const auto end =
203 register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
204 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
205 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
206 ASSERT(it == end);
207 InsertHostThread(static_cast<u32>(core_id));
208 }
209
RegisterHostThreadKernel::KernelCore::Impl210 void RegisterHostThread() {
211 const std::thread::id this_id = std::this_thread::get_id();
212 const auto end =
213 register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
214 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
215 if (it == end) {
216 InsertHostThread(registered_thread_ids++);
217 }
218 }
219
InsertHostThreadKernel::KernelCore::Impl220 void InsertHostThread(u32 value) {
221 const size_t index = num_host_threads++;
222 ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads");
223 register_host_thread_values[index] = value;
224 register_host_thread_keys[index] = std::this_thread::get_id();
225 }
226
GetCurrentHostThreadIDKernel::KernelCore::Impl227 [[nodiscard]] u32 GetCurrentHostThreadID() const {
228 const std::thread::id this_id = std::this_thread::get_id();
229 if (!is_multicore && single_core_thread_id == this_id) {
230 return static_cast<u32>(system.GetCpuManager().CurrentCore());
231 }
232 const auto end =
233 register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
234 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
235 if (it == end) {
236 return Core::INVALID_HOST_THREAD_ID;
237 }
238 return register_host_thread_values[static_cast<size_t>(
239 std::distance(register_host_thread_keys.begin(), it))];
240 }
241
GetCurrentEmuThreadIDKernel::KernelCore::Impl242 Core::EmuThreadHandle GetCurrentEmuThreadID() const {
243 Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
244 result.host_handle = GetCurrentHostThreadID();
245 if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
246 return result;
247 }
248 const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler();
249 const Kernel::Thread* current = sched.GetCurrentThread();
250 if (current != nullptr && !current->IsPhantomMode()) {
251 result.guest_handle = current->GetGlobalHandle();
252 } else {
253 result.guest_handle = InvalidHandle;
254 }
255 return result;
256 }
257
InitializeMemoryLayoutKernel::KernelCore::Impl258 void InitializeMemoryLayout() {
259 // Initialize memory layout
260 constexpr Memory::MemoryLayout layout{Memory::MemoryLayout::GetDefaultLayout()};
261 constexpr std::size_t hid_size{0x40000};
262 constexpr std::size_t font_size{0x1100000};
263 constexpr std::size_t irs_size{0x8000};
264 constexpr std::size_t time_size{0x1000};
265 constexpr PAddr hid_addr{layout.System().StartAddress()};
266 constexpr PAddr font_pa{layout.System().StartAddress() + hid_size};
267 constexpr PAddr irs_addr{layout.System().StartAddress() + hid_size + font_size};
268 constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
269
270 // Initialize memory manager
271 memory_manager = std::make_unique<Memory::MemoryManager>();
272 memory_manager->InitializeManager(Memory::MemoryManager::Pool::Application,
273 layout.Application().StartAddress(),
274 layout.Application().EndAddress());
275 memory_manager->InitializeManager(Memory::MemoryManager::Pool::Applet,
276 layout.Applet().StartAddress(),
277 layout.Applet().EndAddress());
278 memory_manager->InitializeManager(Memory::MemoryManager::Pool::System,
279 layout.System().StartAddress(),
280 layout.System().EndAddress());
281
282 hid_shared_mem = Kernel::SharedMemory::Create(
283 system.Kernel(), system.DeviceMemory(), nullptr,
284 {hid_addr, hid_size / Memory::PageSize}, Memory::MemoryPermission::None,
285 Memory::MemoryPermission::Read, hid_addr, hid_size, "HID:SharedMemory");
286 font_shared_mem = Kernel::SharedMemory::Create(
287 system.Kernel(), system.DeviceMemory(), nullptr,
288 {font_pa, font_size / Memory::PageSize}, Memory::MemoryPermission::None,
289 Memory::MemoryPermission::Read, font_pa, font_size, "Font:SharedMemory");
290 irs_shared_mem = Kernel::SharedMemory::Create(
291 system.Kernel(), system.DeviceMemory(), nullptr,
292 {irs_addr, irs_size / Memory::PageSize}, Memory::MemoryPermission::None,
293 Memory::MemoryPermission::Read, irs_addr, irs_size, "IRS:SharedMemory");
294 time_shared_mem = Kernel::SharedMemory::Create(
295 system.Kernel(), system.DeviceMemory(), nullptr,
296 {time_addr, time_size / Memory::PageSize}, Memory::MemoryPermission::None,
297 Memory::MemoryPermission::Read, time_addr, time_size, "Time:SharedMemory");
298
299 // Allocate slab heaps
300 user_slab_heap_pages = std::make_unique<Memory::SlabHeap<Memory::Page>>();
301
302 // Initialize slab heaps
303 constexpr u64 user_slab_heap_size{0x3de000};
304 user_slab_heap_pages->Initialize(
305 system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase),
306 user_slab_heap_size);
307 }
308
309 std::atomic<u32> next_object_id{0};
310 std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
311 std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
312 std::atomic<u64> next_thread_id{1};
313
314 // Lists all processes that exist in the current session.
315 std::vector<std::shared_ptr<Process>> process_list;
316 Process* current_process = nullptr;
317 Kernel::GlobalScheduler global_scheduler;
318 Kernel::Synchronization synchronization;
319 Kernel::TimeManager time_manager;
320
321 std::shared_ptr<ResourceLimit> system_resource_limit;
322
323 std::shared_ptr<Core::Timing::EventType> preemption_event;
324
325 // This is the kernel's handle table or supervisor handle table which
326 // stores all the objects in place.
327 HandleTable global_handle_table;
328
329 /// Map of named ports managed by the kernel, which can be retrieved using
330 /// the ConnectToPort SVC.
331 NamedPortTable named_ports;
332
333 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
334 std::vector<Kernel::PhysicalCore> cores;
335
336 // 0-3 IDs represent core threads, >3 represent others
337 std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
338
339 // Number of host threads is a relatively high number to avoid overflowing
340 static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
341 std::atomic<size_t> num_host_threads{0};
342 std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
343 register_host_thread_keys{};
344 std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{};
345
346 // Kernel memory management
347 std::unique_ptr<Memory::MemoryManager> memory_manager;
348 std::unique_ptr<Memory::SlabHeap<Memory::Page>> user_slab_heap_pages;
349
350 // Shared memory for services
351 std::shared_ptr<Kernel::SharedMemory> hid_shared_mem;
352 std::shared_ptr<Kernel::SharedMemory> font_shared_mem;
353 std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
354 std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
355
356 std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
357 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
358 std::array<std::unique_ptr<Kernel::Scheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
359
360 bool is_multicore{};
361 std::thread::id single_core_thread_id{};
362
363 std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
364
365 // System context
366 Core::System& system;
367 };
368
KernelCore(Core::System & system)369 KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
~KernelCore()370 KernelCore::~KernelCore() {
371 Shutdown();
372 }
373
SetMulticore(bool is_multicore)374 void KernelCore::SetMulticore(bool is_multicore) {
375 impl->SetMulticore(is_multicore);
376 }
377
Initialize()378 void KernelCore::Initialize() {
379 impl->Initialize(*this);
380 }
381
InitializeCores()382 void KernelCore::InitializeCores() {
383 impl->InitializeCores();
384 }
385
Shutdown()386 void KernelCore::Shutdown() {
387 impl->Shutdown();
388 }
389
GetSystemResourceLimit() const390 std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
391 return impl->system_resource_limit;
392 }
393
RetrieveThreadFromGlobalHandleTable(Handle handle) const394 std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
395 return impl->global_handle_table.Get<Thread>(handle);
396 }
397
AppendNewProcess(std::shared_ptr<Process> process)398 void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
399 impl->process_list.push_back(std::move(process));
400 }
401
MakeCurrentProcess(Process * process)402 void KernelCore::MakeCurrentProcess(Process* process) {
403 impl->MakeCurrentProcess(process);
404 }
405
CurrentProcess()406 Process* KernelCore::CurrentProcess() {
407 return impl->current_process;
408 }
409
CurrentProcess() const410 const Process* KernelCore::CurrentProcess() const {
411 return impl->current_process;
412 }
413
GetProcessList() const414 const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const {
415 return impl->process_list;
416 }
417
GlobalScheduler()418 Kernel::GlobalScheduler& KernelCore::GlobalScheduler() {
419 return impl->global_scheduler;
420 }
421
GlobalScheduler() const422 const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
423 return impl->global_scheduler;
424 }
425
Scheduler(std::size_t id)426 Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) {
427 return *impl->schedulers[id];
428 }
429
Scheduler(std::size_t id) const430 const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const {
431 return *impl->schedulers[id];
432 }
433
PhysicalCore(std::size_t id)434 Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
435 return impl->cores[id];
436 }
437
PhysicalCore(std::size_t id) const438 const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
439 return impl->cores[id];
440 }
441
CurrentPhysicalCore()442 Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
443 u32 core_id = impl->GetCurrentHostThreadID();
444 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
445 return impl->cores[core_id];
446 }
447
CurrentPhysicalCore() const448 const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
449 u32 core_id = impl->GetCurrentHostThreadID();
450 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
451 return impl->cores[core_id];
452 }
453
CurrentScheduler()454 Kernel::Scheduler& KernelCore::CurrentScheduler() {
455 u32 core_id = impl->GetCurrentHostThreadID();
456 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
457 return *impl->schedulers[core_id];
458 }
459
CurrentScheduler() const460 const Kernel::Scheduler& KernelCore::CurrentScheduler() const {
461 u32 core_id = impl->GetCurrentHostThreadID();
462 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
463 return *impl->schedulers[core_id];
464 }
465
Interrupts()466 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() {
467 return impl->interrupts;
468 }
469
Interrupts() const470 const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts()
471 const {
472 return impl->interrupts;
473 }
474
Synchronization()475 Kernel::Synchronization& KernelCore::Synchronization() {
476 return impl->synchronization;
477 }
478
Synchronization() const479 const Kernel::Synchronization& KernelCore::Synchronization() const {
480 return impl->synchronization;
481 }
482
TimeManager()483 Kernel::TimeManager& KernelCore::TimeManager() {
484 return impl->time_manager;
485 }
486
TimeManager() const487 const Kernel::TimeManager& KernelCore::TimeManager() const {
488 return impl->time_manager;
489 }
490
GetExclusiveMonitor()491 Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
492 return *impl->exclusive_monitor;
493 }
494
GetExclusiveMonitor() const495 const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
496 return *impl->exclusive_monitor;
497 }
498
InvalidateAllInstructionCaches()499 void KernelCore::InvalidateAllInstructionCaches() {
500 for (auto& physical_core : impl->cores) {
501 physical_core.ArmInterface().ClearInstructionCache();
502 }
503 }
504
InvalidateCpuInstructionCacheRange(VAddr addr,std::size_t size)505 void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
506 for (auto& physical_core : impl->cores) {
507 if (!physical_core.IsInitialized()) {
508 continue;
509 }
510 physical_core.ArmInterface().InvalidateCacheRange(addr, size);
511 }
512 }
513
PrepareReschedule(std::size_t id)514 void KernelCore::PrepareReschedule(std::size_t id) {
515 // TODO: Reimplement, this
516 }
517
AddNamedPort(std::string name,std::shared_ptr<ClientPort> port)518 void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
519 impl->named_ports.emplace(std::move(name), std::move(port));
520 }
521
FindNamedPort(const std::string & name)522 KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) {
523 return impl->named_ports.find(name);
524 }
525
FindNamedPort(const std::string & name) const526 KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort(
527 const std::string& name) const {
528 return impl->named_ports.find(name);
529 }
530
IsValidNamedPort(NamedPortTable::const_iterator port) const531 bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
532 return port != impl->named_ports.cend();
533 }
534
CreateNewObjectID()535 u32 KernelCore::CreateNewObjectID() {
536 return impl->next_object_id++;
537 }
538
CreateNewThreadID()539 u64 KernelCore::CreateNewThreadID() {
540 return impl->next_thread_id++;
541 }
542
CreateNewKernelProcessID()543 u64 KernelCore::CreateNewKernelProcessID() {
544 return impl->next_kernel_process_id++;
545 }
546
CreateNewUserProcessID()547 u64 KernelCore::CreateNewUserProcessID() {
548 return impl->next_user_process_id++;
549 }
550
GlobalHandleTable()551 Kernel::HandleTable& KernelCore::GlobalHandleTable() {
552 return impl->global_handle_table;
553 }
554
GlobalHandleTable() const555 const Kernel::HandleTable& KernelCore::GlobalHandleTable() const {
556 return impl->global_handle_table;
557 }
558
RegisterCoreThread(std::size_t core_id)559 void KernelCore::RegisterCoreThread(std::size_t core_id) {
560 impl->RegisterCoreThread(core_id);
561 }
562
RegisterHostThread()563 void KernelCore::RegisterHostThread() {
564 impl->RegisterHostThread();
565 }
566
GetCurrentHostThreadID() const567 u32 KernelCore::GetCurrentHostThreadID() const {
568 return impl->GetCurrentHostThreadID();
569 }
570
GetCurrentEmuThreadID() const571 Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
572 return impl->GetCurrentEmuThreadID();
573 }
574
MemoryManager()575 Memory::MemoryManager& KernelCore::MemoryManager() {
576 return *impl->memory_manager;
577 }
578
MemoryManager() const579 const Memory::MemoryManager& KernelCore::MemoryManager() const {
580 return *impl->memory_manager;
581 }
582
GetUserSlabHeapPages()583 Memory::SlabHeap<Memory::Page>& KernelCore::GetUserSlabHeapPages() {
584 return *impl->user_slab_heap_pages;
585 }
586
GetUserSlabHeapPages() const587 const Memory::SlabHeap<Memory::Page>& KernelCore::GetUserSlabHeapPages() const {
588 return *impl->user_slab_heap_pages;
589 }
590
GetHidSharedMem()591 Kernel::SharedMemory& KernelCore::GetHidSharedMem() {
592 return *impl->hid_shared_mem;
593 }
594
GetHidSharedMem() const595 const Kernel::SharedMemory& KernelCore::GetHidSharedMem() const {
596 return *impl->hid_shared_mem;
597 }
598
GetFontSharedMem()599 Kernel::SharedMemory& KernelCore::GetFontSharedMem() {
600 return *impl->font_shared_mem;
601 }
602
GetFontSharedMem() const603 const Kernel::SharedMemory& KernelCore::GetFontSharedMem() const {
604 return *impl->font_shared_mem;
605 }
606
GetIrsSharedMem()607 Kernel::SharedMemory& KernelCore::GetIrsSharedMem() {
608 return *impl->irs_shared_mem;
609 }
610
GetIrsSharedMem() const611 const Kernel::SharedMemory& KernelCore::GetIrsSharedMem() const {
612 return *impl->irs_shared_mem;
613 }
614
GetTimeSharedMem()615 Kernel::SharedMemory& KernelCore::GetTimeSharedMem() {
616 return *impl->time_shared_mem;
617 }
618
GetTimeSharedMem() const619 const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const {
620 return *impl->time_shared_mem;
621 }
622
Suspend(bool in_suspention)623 void KernelCore::Suspend(bool in_suspention) {
624 const bool should_suspend = exception_exited || in_suspention;
625 {
626 SchedulerLock lock(*this);
627 ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep;
628 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
629 impl->suspend_threads[i]->SetStatus(status);
630 }
631 }
632 }
633
IsMulticore() const634 bool KernelCore::IsMulticore() const {
635 return impl->is_multicore;
636 }
637
ExceptionalExit()638 void KernelCore::ExceptionalExit() {
639 exception_exited = true;
640 Suspend(true);
641 }
642
EnterSVCProfile()643 void KernelCore::EnterSVCProfile() {
644 std::size_t core = impl->GetCurrentHostThreadID();
645 impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC));
646 }
647
ExitSVCProfile()648 void KernelCore::ExitSVCProfile() {
649 std::size_t core = impl->GetCurrentHostThreadID();
650 MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
651 }
652
653 } // namespace Kernel
654