diff --git a/libraries/libmesosphere/include/mesosphere.hpp b/libraries/libmesosphere/include/mesosphere.hpp
index cd979eb25..ea3442e7e 100644
--- a/libraries/libmesosphere/include/mesosphere.hpp
+++ b/libraries/libmesosphere/include/mesosphere.hpp
@@ -37,9 +37,13 @@
#include "mesosphere/kern_k_memory_layout.hpp"
/* Core functionality. */
-#include "mesosphere/kern_select_interrupts.hpp"
+#include "mesosphere/kern_select_interrupt_manager.hpp"
+#include "mesosphere/kern_k_spin_lock.hpp"
#include "mesosphere/kern_k_page_heap.hpp"
#include "mesosphere/kern_k_memory_manager.hpp"
+#include "mesosphere/kern_k_interrupt_task_manager.hpp"
+#include "mesosphere/kern_k_core_local_region.hpp"
+#include "mesosphere/kern_kernel.hpp"
/* Supervisor Calls. */
#include "mesosphere/kern_svc.hpp"
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp
new file mode 100644
index 000000000..6f912bf22
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include
+
+namespace ams::kern::arm64 {
+
+ class KHardwareTimer : public KHardwareTimerBase {
+ public:
+ static constexpr s32 InterruptId = 30; /* Nintendo uses the non-secure timer interrupt. */
+ public:
+ constexpr KHardwareTimer() : KHardwareTimerBase() { /* ... */ }
+
+ virtual void DoTask() override;
+
+ /* TODO: Actually implement more of KHardwareTimer, */
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_controller.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_controller.hpp
new file mode 100644
index 000000000..e76df1cf3
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_controller.hpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include
+#include
+
+namespace ams::kern::arm64 {
+
+ struct GicDistributor {
+ u32 ctlr;
+ u32 typer;
+ u32 iidr;
+ u32 reserved_0x0c;
+ u32 statusr;
+ u32 reserved_0x14[3];
+ u32 impldef_0x20[8];
+ u32 setspi_nsr;
+ u32 reserved_0x44;
+ u32 clrspi_nsr;
+ u32 reserved_0x4c;
+ u32 setspi_sr;
+ u32 reserved_0x54;
+ u32 clrspi_sr;
+ u32 reserved_0x5c[9];
+ u32 igroupr[32];
+ u32 isenabler[32];
+ u32 icenabler[32];
+ u32 ispendr[32];
+ u32 icpendr[32];
+ u32 isactiver[32];
+ u32 icactiver[32];
+ u8 ipriorityr[1020];
+ u32 _0x7fc;
+ u8 itargetsr[1020];
+ u32 _0xbfc;
+ u32 icfgr[64];
+ u32 igrpmodr[32];
+ u32 _0xd80[32];
+ u32 nsacr[64];
+ u32 sgir;
+ u32 _0xf04[3];
+ u32 cpendsgir[4];
+ u32 spendsgir[4];
+ u32 reserved_0xf30[52];
+ };
+ static_assert(std::is_pod::value);
+ static_assert(sizeof(GicDistributor) == 0x1000);
+
+ struct GicController {
+ u32 ctlr;
+ u32 pmr;
+ u32 bpr;
+ u32 iar;
+ u32 eoir;
+ u32 rpr;
+ u32 hppir;
+ u32 abpr;
+ u32 aiar;
+ u32 aeoir;
+ u32 ahppir;
+ u32 statusr;
+ u32 reserved_30[4];
+ u32 impldef_40[36];
+ u32 apr[4];
+ u32 nsapr[4];
+ u32 reserved_f0[3];
+ u32 iidr;
+ u32 reserved_100[960];
+ u32 dir;
+ u32 _0x1004[1023];
+ };
+ static_assert(std::is_pod::value);
+ static_assert(sizeof(GicController) == 0x2000);
+
+ struct KInterruptController {
+ NON_COPYABLE(KInterruptController);
+ NON_MOVEABLE(KInterruptController);
+ public:
+ static constexpr size_t NumLocalInterrupts = 32;
+ static constexpr size_t NumGlobalInterrupts = 988;
+ static constexpr size_t NumInterrupts = NumLocalInterrupts + NumGlobalInterrupts;
+ public:
+ struct LocalState {
+ u32 local_isenabler[NumLocalInterrupts / 32];
+ u32 local_ipriorityr[NumLocalInterrupts / 4];
+ u32 local_targetsr[NumLocalInterrupts / 4];
+ u32 local_icfgr[NumLocalInterrupts / 16];
+ };
+
+ struct GlobalState {
+ u32 global_isenabler[NumGlobalInterrupts / 32];
+ u32 global_ipriorityr[NumGlobalInterrupts / 4];
+ u32 global_targetsr[NumGlobalInterrupts / 4];
+ u32 global_icfgr[NumGlobalInterrupts / 16];
+ };
+ private:
+ static inline volatile GicDistributor *s_gicd;
+ static inline volatile GicController *s_gicc;
+ static inline u32 s_mask[cpu::NumCores];
+ private:
+ volatile GicDistributor *gicd;
+ volatile GicController *gicc;
+ public:
+ KInterruptController() { /* Don't initialize anything -- this will be taken care of by ::Initialize() */ }
+
+ /* TODO: Actually implement KInterruptController functionality. */
+ };
+}
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp
new file mode 100644
index 000000000..132e24eee
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include
+#include
+#include
+#include
+
+namespace ams::kern::arm64 {
+
+ class KInterruptManager {
+ NON_COPYABLE(KInterruptManager);
+ NON_MOVEABLE(KInterruptManager);
+ private:
+ struct KCoreLocalInterruptEntry {
+ KInterruptHandler *handler;
+ bool manually_cleared;
+ bool needs_clear;
+ u8 priority;
+ };
+
+ struct KGlobalInterruptEntry {
+ KInterruptHandler *handler;
+ bool manually_cleared;
+ bool needs_clear;
+ };
+ private:
+ static inline KSpinLock s_lock;
+ static inline KGlobalInterruptEntry s_global_interrupts[KInterruptController::NumGlobalInterrupts];
+ static inline KInterruptController::GlobalState s_global_state;
+ static inline bool s_global_state_saved;
+ private:
+ KCoreLocalInterruptEntry core_local_interrupts[KInterruptController::NumLocalInterrupts];
+ KInterruptController interrupt_controller;
+ KInterruptController::LocalState local_state;
+ bool local_state_saved;
+ public:
+ KInterruptManager() : local_state_saved(false) { /* Leave things mostly uninitalized. We'll call ::Initialize() later. */ }
+ /* TODO: Actually implement KInterruptManager functionality. */
+ public:
+ static ALWAYS_INLINE u32 DisableInterrupts() {
+ u64 intr_state;
+ __asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
+ __asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"(intr_state | 0x80));
+ return intr_state;
+ }
+
+ static ALWAYS_INLINE u32 EnableInterrupts() {
+ u64 intr_state;
+ __asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
+ __asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"(intr_state & 0x7F));
+ return intr_state;
+ }
+
+ static ALWAYS_INLINE void RestoreInterrupts(u32 intr_state) {
+ u64 cur_state;
+ __asm__ __volatile__("mrs %[cur_state], daif" : [cur_state]"=r"(cur_state));
+ __asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"((cur_state & 0x7F) | (intr_state & 0x80)));
+ }
+
+ static ALWAYS_INLINE bool AreInterruptsEnabled() {
+ u64 intr_state;
+ __asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
+ return (intr_state & 0x80) == 0;
+ }
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_spin_lock.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_spin_lock.hpp
new file mode 100644
index 000000000..adf87720e
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_spin_lock.hpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include
+
+namespace ams::kern::arm64 {
+
+ class KNotAlignedSpinLock {
+ private:
+ u32 packed_tickets;
+ public:
+ constexpr KNotAlignedSpinLock() : packed_tickets(0) { /* ... */ }
+
+ void Lock() {
+ u32 tmp0, tmp1;
+
+ __asm__ __volatile__(
+ " prfm pstl1keep, %[packed_tickets]\n"
+ "loop1:\n"
+ " ldaxr %w[tmp0], %[packed_tickets]\n"
+ " add %w[tmp0], %w[tmp0], #0x10000\n"
+ " stxr %w[tmp1], %w[tmp0], %[packed_tickets]\n"
+ " cbnz %w[tmp1], loop1\n"
+ " \n"
+ " and %w[tmp1], %w[tmp0], #0xFFFF\n"
+ " cmp %w[tmp1], %w[tmp0], lsr #16\n"
+ " b.eq done"
+ " sevl\n"
+ "loop2:\n"
+ " wfe\n"
+ " ldaxrh %w[tmp1], %[packed_tickets]\n"
+ " cmp %w[tmp1], %w[tmp0], lsr #16\n"
+ " b.ne loop2\n"
+ "done:\n"
+ : [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [packed_tickets]"+Q"(this->packed_tickets)
+ :
+ : "cc", "memory"
+ );
+ }
+
+ void Unlock() {
+ const u32 value = this->packed_tickets + 1;
+ __asm__ __volatile__(
+ " stlrh %w[value], %[packed_tickets]\n"
+ : [packed_tickets]"+Q"(this->packed_tickets)
+ : [value]"r"(value)
+ : "memory"
+ );
+ }
+ };
+ static_assert(sizeof(KNotAlignedSpinLock) == sizeof(u32));
+
+ class KAlignedSpinLock {
+ private:
+ alignas(cpu::DataCacheLineSize) u16 current_ticket;
+ alignas(cpu::DataCacheLineSize) u16 next_ticket;
+ public:
+ constexpr KAlignedSpinLock() : current_ticket(0), next_ticket(0) { /* ... */ }
+
+ void Lock() {
+ u32 tmp0, tmp1, got_lock;
+
+ __asm__ __volatile__(
+ " prfm pstl1keep, %[next_ticket]\n"
+ "loop1:\n"
+ " ldaxrh %w[tmp0], %[next_ticket]\n"
+ " add %w[tmp1], %w[tmp0], #0x1\n"
+ " stxrh %w[got_lock], %w[tmp1], %[next_ticket]\n"
+ " cbnz %w[got_lock], loop1\n"
+ " \n"
+ " sevl\n"
+ "loop2:\n"
+ " wfe\n"
+ " ldaxrh %w[tmp1], %[current_ticket]\n"
+ " cmp %w[tmp1], %w[tmp0]\n"
+ " b.ne loop2\n"
+ : [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [got_lock]"=&r"(got_lock), [next_ticket]"+Q"(this->next_ticket)
+ : [current_ticket]"Q"(this->current_ticket)
+ : "cc", "memory"
+ );
+ }
+
+ void Unlock() {
+ const u32 value = this->current_ticket + 1;
+ __asm__ __volatile__(
+ " stlrh %w[value], %[current_ticket]\n"
+ : [current_ticket]"+Q"(this->current_ticket)
+ : [value]"r"(value)
+ : "memory"
+ );
+ }
+ };
+ static_assert(sizeof(KAlignedSpinLock) == 2 * cpu::DataCacheLineSize);
+
+ using KSpinLock = KAlignedSpinLock;
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_core_local_region.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_core_local_region.hpp
new file mode 100644
index 000000000..4422df408
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_core_local_region.hpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ams::kern {
+
+ struct KCoreLocalContext {
+ KCurrentContext current;
+ KScheduler scheduler;
+ KInterruptTaskManager interrupt_task_manager;
+ KInterruptManager interrupt_manager;
+ KHardwareTimer hardware_timer;
+ /* Everything after this point is for debugging. */
+ /* Retail kernel doesn't even consistently update these fields. */
+ u64 num_sw_interrupts;
+ u64 num_hw_interrupts;
+ std::atomic num_svc;
+ u64 num_process_switches;
+ u64 num_thread_switches;
+ u64 num_fpu_switches;
+ u64 num_scheduler_updates;
+ u64 num_invoked_scheduler_updates;
+ std::atomic num_specific_svc[0x80];
+ u32 perf_counters[6];
+ };
+ static_assert(sizeof(KCoreLocalContext) < KMemoryManager::PageSize);
+
+ struct KCoreLocalPage {
+ KCoreLocalContext context;
+ u8 padding[KMemoryManager::PageSize - sizeof(KCoreLocalContext)];
+ };
+ static_assert(sizeof(KCoreLocalPage) == KMemoryManager::PageSize);
+
+ struct KCoreLocalRegion {
+ KCoreLocalPage current;
+ KCoreLocalPage absolute[cpu::NumCores];
+ };
+ static_assert(sizeof(KCoreLocalRegion) == KMemoryManager::PageSize * (1 + cpu::NumCores));
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_current_context.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_current_context.hpp
new file mode 100644
index 000000000..1cf1abb69
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_current_context.hpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::kern {
+
+ class KThread;
+ class KProcess;
+ class KScheduler;
+ class KInterruptTaskManager;
+
+ struct KCurrentContext {
+ KThread *current_thread;
+ KProcess *current_process;
+ KScheduler *scheduler;
+ KInterruptTaskManager *interrupt_task_manager;
+ s32 core_id;
+ void *exception_stack_bottom;
+ };
+ static_assert(std::is_pod::value);
+ static_assert(sizeof(KCurrentContext) <= cpu::DataCacheLineSize);
+
+ namespace impl {
+
+ ALWAYS_INLINE KCurrentContext &GetCurrentContext() {
+ return *reinterpret_cast(cpu::GetCoreLocalRegionAddress());
+ }
+
+ }
+
+ ALWAYS_INLINE KThread *GetCurrentThreadPointer() {
+ return impl::GetCurrentContext().current_thread;
+ }
+
+ ALWAYS_INLINE KThread &GetCurrentThread() {
+ return *GetCurrentThreadPointer();
+ }
+
+ ALWAYS_INLINE KProcess *GetCurrentProcessPointer() {
+ return impl::GetCurrentContext().current_process;
+ }
+
+ ALWAYS_INLINE KProcess &GetCurrentProcess() {
+ return *GetCurrentProcessPointer();
+ }
+
+ ALWAYS_INLINE KScheduler *GetCurrentSchedulerPointer() {
+ return impl::GetCurrentContext().scheduler;
+ }
+
+ ALWAYS_INLINE KScheduler &GetCurrentScheduler() {
+ return *GetCurrentSchedulerPointer();
+ }
+
+ ALWAYS_INLINE KInterruptTaskManager *GetCurrentInterruptTaskManagerPointer() {
+ return impl::GetCurrentContext().interrupt_task_manager;
+ }
+
+ ALWAYS_INLINE KInterruptTaskManager &GetCurrentInterruptTaskManager() {
+ return *GetCurrentInterruptTaskManagerPointer();
+ }
+
+ ALWAYS_INLINE s32 GetCurrentCoreId() {
+ return impl::GetCurrentContext().core_id;
+ }
+
+ ALWAYS_INLINE void SetCurrentThread(KThread *new_thread) {
+ impl::GetCurrentContext().current_thread = new_thread;
+ }
+
+ ALWAYS_INLINE void SetCurrentProcess(KProcess *new_process) {
+ impl::GetCurrentContext().current_process = new_process;
+ }
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_hardware_timer_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_hardware_timer_base.hpp
new file mode 100644
index 000000000..c03d372ca
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_hardware_timer_base.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include
+#include
+#include
+
+namespace ams::kern {
+
+ class KHardwareTimerBase : public KInterruptTask {
+ private:
+ using TimerTaskTree = util::IntrusiveRedBlackTreeBaseTraits::TreeType;
+ private:
+ KSpinLock lock;
+ TimerTaskTree task_tree;
+ KTimerTask *next_task;
+ public:
+ constexpr KHardwareTimerBase() : lock(), task_tree(), next_task(nullptr) { /* ... */ }
+
+ virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { return this; }
+ protected:
+ KSpinLock &GetLock() { return this->lock; }
+
+ /* TODO: Actually implement more of KHardwareTimerBase */
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task.hpp
new file mode 100644
index 000000000..642fa3203
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+
+namespace ams::kern {
+
+ class KInterruptTask;
+
+ class KInterruptHandler {
+ public:
+ virtual KInterruptTask *OnInterrupt(s32 interrupt_id) = 0;
+ };
+
+ class KInterruptTask : public KInterruptHandler {
+ private:
+ KInterruptTask *next_task;
+ public:
+ constexpr ALWAYS_INLINE KInterruptTask() : next_task(nullptr) { /* ... */ }
+
+ ALWAYS_INLINE KInterruptTask *GetNextTask() const {
+ return this->next_task;
+ }
+
+ ALWAYS_INLINE void SetNextTask(KInterruptTask *t) {
+ this->next_task = t;
+ }
+
+ virtual void DoTask() = 0;
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task_manager.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task_manager.hpp
new file mode 100644
index 000000000..cc3111b7a
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task_manager.hpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::kern {
+
+ class KThread;
+
+ class KInterruptTaskManager {
+ private:
+ class TaskQueue {
+ private:
+ KInterruptTask *head;
+ KInterruptTask *tail;
+ public:
+ constexpr TaskQueue() : head(nullptr), tail(nullptr) { /* ... */ }
+
+ ALWAYS_INLINE KInterruptTask *GetHead() { return this->head; }
+ ALWAYS_INLINE bool IsEmpty() const { return this->head == nullptr; }
+ ALWAYS_INLINE void Clear() { this->head = nullptr; this->tail = nullptr; }
+
+ void Enqueue(KInterruptTask *task);
+ void Dequeue();
+ };
+ private:
+ TaskQueue task_queue;
+ KThread *thread;
+ public:
+ /* TODO: Actually implement KInterruptTaskManager. This is a placeholder. */
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp
index 020757b5d..cabb55c4c 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp
@@ -402,6 +402,18 @@ namespace ams::kern {
return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_KernelMiscMainStack, static_cast(core_id))->GetEndAddress();
}
+ static NOINLINE KVirtualAddress GetIdleStackTopAddress(s32 core_id) {
+ return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_KernelMiscIdleStack, static_cast(core_id))->GetEndAddress();
+ }
+
+ static NOINLINE KVirtualAddress GetExceptionStackBottomAddress(s32 core_id) {
+ return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_KernelMiscExceptionStack, static_cast(core_id))->GetAddress();
+ }
+
+ static NOINLINE KVirtualAddress GetCoreLocalRegionAddress() {
+ return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_CoreLocal)->GetAddress();
+ }
+
static void InitializeLinearMemoryBlockTrees(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start);
};
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp
new file mode 100644
index 000000000..7476d1aea
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::kern {
+
+ class KScheduler {
+ NON_COPYABLE(KScheduler);
+ NON_MOVEABLE(KScheduler);
+ public:
+ struct SchedulingState {
+ std::atomic needs_scheduling;
+ bool interrupt_task_thread_runnable;
+ bool should_count_idle;
+ u64 idle_count;
+ KThread *highest_priority_thread;
+ void *idle_thread_stack;
+ };
+ private:
+ SchedulingState state;
+ bool is_active;
+ s32 core_id;
+ KThread *prev_thread;
+ u64 last_context_switch_time;
+ KThread *idle_thread;
+ public:
+ KScheduler();
+ /* TODO: Actually implement KScheduler. This is a placeholder. */
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_spin_lock.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_spin_lock.hpp
new file mode 100644
index 000000000..55706313c
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_spin_lock.hpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include "kern_panic.hpp"
+
+#if defined(ATMOSPHERE_ARCH_ARM64)
+
+ #include
+ namespace ams::kern {
+ using ams::kern::arm64::KAlignedSpinLock;
+ using ams::kern::arm64::KNotAlignedSpinLock;
+ using ams::kern::arm64::KSpinLock;
+ }
+
+#else
+
+ #error "Unknown architecture for KInterruptManager"
+
+#endif
+
+
+namespace ams::kern {
+
+ class KScopedSpinLock {
+ private:
+ KSpinLock *lock_ptr;
+ public:
+ explicit ALWAYS_INLINE KScopedSpinLock(KSpinLock *l) : lock_ptr(l) {
+ this->lock_ptr->Lock();
+ }
+ ALWAYS_INLINE ~KScopedSpinLock() {
+ this->lock_ptr->Unlock();
+ }
+ };
+
+ class KScopedAlignedSpinLock {
+ private:
+ KAlignedSpinLock *lock_ptr;
+ public:
+ explicit ALWAYS_INLINE KScopedAlignedSpinLock(KAlignedSpinLock *l) : lock_ptr(l) {
+ this->lock_ptr->Lock();
+ }
+ ALWAYS_INLINE ~KScopedAlignedSpinLock() {
+ this->lock_ptr->Unlock();
+ }
+ };
+
+ class KScopedNotAlignedSpinLock {
+ private:
+ KNotAlignedSpinLock *lock_ptr;
+ public:
+ explicit ALWAYS_INLINE KScopedNotAlignedSpinLock(KNotAlignedSpinLock *l) : lock_ptr(l) {
+ this->lock_ptr->Lock();
+ }
+ ALWAYS_INLINE ~KScopedNotAlignedSpinLock() {
+ this->lock_ptr->Unlock();
+ }
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp
new file mode 100644
index 000000000..8959a381e
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+
+namespace ams::kern {
+
+
+ class KThread {
+ /* TODO: This should be a KAutoObject, and this is a placeholder definition. */
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_timer_task.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_timer_task.hpp
new file mode 100644
index 000000000..d57899ce8
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_timer_task.hpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::kern {
+
+ class KTimerTask : public util::IntrusiveRedBlackTreeBaseNode {
+ private:
+ s64 time;
+ public:
+ static constexpr ALWAYS_INLINE int Compare(const KTimerTask &lhs, const KTimerTask &rhs) {
+ if (lhs.GetTime() < rhs.GetTime()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ public:
+ constexpr ALWAYS_INLINE KTimerTask() : time(0) { /* ... */ }
+
+ constexpr ALWAYS_INLINE void SetTime(s64 t) {
+ this->time = t;
+ }
+
+ constexpr ALWAYS_INLINE s64 GetTime() const {
+ return this->time;
+ }
+
+ virtual void OnTimer() = 0;
+
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp
new file mode 100644
index 000000000..4eb1e97d5
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include
+#include
+#include
+
+namespace ams::kern {
+
+ class Kernel {
+ public:
+ enum class State : u8 {
+ Invalid = 0,
+ Initializing = 1,
+ Initialized = 2,
+ };
+ private:
+ static inline State s_state = State::Invalid;
+ public:
+ static void Initialize(s32 core_id);
+
+ static ALWAYS_INLINE State GetState() { return s_state; }
+ static ALWAYS_INLINE void SetState(State state) { s_state = state; }
+ };
+
+}
diff --git a/libraries/libmesosphere/include/mesosphere/kern_select_hardware_timer.hpp b/libraries/libmesosphere/include/mesosphere/kern_select_hardware_timer.hpp
new file mode 100644
index 000000000..db8d6e4f4
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_select_hardware_timer.hpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include "kern_panic.hpp"
+
+#if defined(ATMOSPHERE_ARCH_ARM64)
+
+ #include
+ namespace ams::kern {
+ using ams::kern::arm64::KHardwareTimer;
+ }
+
+#else
+
+ #error "Unknown architecture for KHardwareTimer"
+
+#endif
diff --git a/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_controller.hpp b/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_controller.hpp
new file mode 100644
index 000000000..e9bbd2ff6
--- /dev/null
+++ b/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_controller.hpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include "kern_panic.hpp"
+
+#if defined(ATMOSPHERE_ARCH_ARM64)
+
+ #include
+ namespace ams::kern {
+ using ams::kern::arm64::KInterruptController;
+ }
+
+#else
+
+ #error "Unknown architecture for KInterruptController"
+
+#endif
diff --git a/libraries/libmesosphere/include/mesosphere/kern_select_interrupts.hpp b/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp
similarity index 58%
rename from libraries/libmesosphere/include/mesosphere/kern_select_interrupts.hpp
rename to libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp
index 312450b7c..cab08dd0d 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_select_interrupts.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp
@@ -17,26 +17,42 @@
#include
#include "kern_panic.hpp"
-namespace ams::kern {
+#if defined(ATMOSPHERE_ARCH_ARM64)
- /* TODO: Actually select between architecture-specific interrupt code. */
+ #include
+ namespace ams::kern {
+ using ams::kern::arm64::KInterruptManager;
+ }
+
+#else
+
+ #error "Unknown architecture for KInterruptManager"
+
+#endif
+
+
+namespace ams::kern {
/* Enable or disable interrupts for the lifetime of an object. */
class KScopedInterruptDisable {
NON_COPYABLE(KScopedInterruptDisable);
NON_MOVEABLE(KScopedInterruptDisable);
+ private:
+ u32 prev_intr_state;
public:
- KScopedInterruptDisable();
- ~KScopedInterruptDisable();
+ ALWAYS_INLINE KScopedInterruptDisable() : prev_intr_state(KInterruptManager::DisableInterrupts()) { /* ... */ }
+ ~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(prev_intr_state); }
};
class KScopedInterruptEnable {
NON_COPYABLE(KScopedInterruptEnable);
NON_MOVEABLE(KScopedInterruptEnable);
+ private:
+ u32 prev_intr_state;
public:
- KScopedInterruptEnable();
- ~KScopedInterruptEnable();
+ ALWAYS_INLINE KScopedInterruptEnable() : prev_intr_state(KInterruptManager::EnableInterrupts()) { /* ... */ }
+ ~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(prev_intr_state); }
};
}
diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp
new file mode 100644
index 000000000..6dbf242b3
--- /dev/null
+++ b/libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+namespace ams::kern::arm64 {
+
+ void KHardwareTimer::DoTask() {
+ /* TODO: Actually implement this. */
+ }
+
+}
diff --git a/mesosphere/kernel_ldr/source/kern_k_scoped_interrupt.cpp b/libraries/libmesosphere/source/kern_k_interrupt_task_manager.cpp
similarity index 54%
rename from mesosphere/kernel_ldr/source/kern_k_scoped_interrupt.cpp
rename to libraries/libmesosphere/source/kern_k_interrupt_task_manager.cpp
index 00ef6f718..8daa3d49d 100644
--- a/mesosphere/kernel_ldr/source/kern_k_scoped_interrupt.cpp
+++ b/libraries/libmesosphere/source/kern_k_interrupt_task_manager.cpp
@@ -17,20 +17,24 @@
namespace ams::kern {
- inline KScopedInterruptDisable::KScopedInterruptDisable() {
- /* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
+ void KInterruptTaskManager::TaskQueue::Enqueue(KInterruptTask *task) {
+ /* Insert the task into the queue. */
+ if (this->tail != nullptr) {
+ this->tail->SetNextTask(task);
+ } else {
+ this->head = task;
+ }
+
+ this->tail = task;
}
- inline KScopedInterruptDisable::~KScopedInterruptDisable() {
- /* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
- }
-
- inline KScopedInterruptEnable::KScopedInterruptEnable() {
- /* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
- }
-
- inline KScopedInterruptEnable::~KScopedInterruptEnable() {
- /* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
+ void KInterruptTaskManager::TaskQueue::Dequeue() {
+ if (this->head == this->tail) {
+ this->head = nullptr;
+ this->tail = nullptr;
+ } else {
+ this->head = this->head->GetNextTask();
+ }
}
}
diff --git a/libraries/libmesosphere/source/kern_k_scoped_interrupt.cpp b/libraries/libmesosphere/source/kern_k_scheduler.cpp
similarity index 60%
rename from libraries/libmesosphere/source/kern_k_scoped_interrupt.cpp
rename to libraries/libmesosphere/source/kern_k_scheduler.cpp
index b342684db..1ec51bd8a 100644
--- a/libraries/libmesosphere/source/kern_k_scoped_interrupt.cpp
+++ b/libraries/libmesosphere/source/kern_k_scheduler.cpp
@@ -17,20 +17,15 @@
namespace ams::kern {
- WEAK_SYMBOL KScopedInterruptDisable::KScopedInterruptDisable() {
- /* TODO: Disable interrupts. */
- }
-
- WEAK_SYMBOL KScopedInterruptDisable::~KScopedInterruptDisable() {
- /* TODO: un-disable interrupts. */
- }
-
- WEAK_SYMBOL KScopedInterruptEnable::KScopedInterruptEnable() {
- /* TODO: Enable interrupts. */
- }
-
- WEAK_SYMBOL KScopedInterruptEnable::~KScopedInterruptEnable() {
- /* TODO: un-enable interrupts. */
+ KScheduler::KScheduler()
+ : is_active(false), core_id(0), prev_thread(nullptr), last_context_switch_time(0), idle_thread(nullptr)
+ {
+ this->state.needs_scheduling = true;
+ this->state.interrupt_task_thread_runnable = false;
+ this->state.should_count_idle = false;
+ this->state.idle_count = 0;
+ this->state.idle_thread_stack = nullptr;
+ this->state.highest_priority_thread = nullptr;
}
}
diff --git a/libraries/libmesosphere/source/kern_kernel.cpp b/libraries/libmesosphere/source/kern_kernel.cpp
new file mode 100644
index 000000000..e00cdb563
--- /dev/null
+++ b/libraries/libmesosphere/source/kern_kernel.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+namespace ams::kern {
+
+ NOINLINE void Kernel::Initialize(s32 core_id) {
+ /* Construct the core local region object in place. */
+ KCoreLocalContext *clc = GetPointer(KMemoryLayout::GetCoreLocalRegionAddress());
+ new (clc) KCoreLocalContext;
+
+ /* Set the core local region address into the global register. */
+ cpu::SetCoreLocalRegionAddress(reinterpret_cast(clc));
+
+ /* Initialize current context. */
+ clc->current.current_thread = nullptr;
+ clc->current.current_process = nullptr;
+ clc->current.scheduler = std::addressof(clc->scheduler);
+ clc->current.interrupt_task_manager = std::addressof(clc->interrupt_task_manager);
+ clc->current.core_id = core_id;
+ clc->current.exception_stack_bottom = GetVoidPointer(KMemoryLayout::GetExceptionStackBottomAddress(core_id));
+
+ /* Clear debugging counters. */
+ clc->num_sw_interrupts = 0;
+ clc->num_hw_interrupts = 0;
+ clc->num_svc = 0;
+ clc->num_process_switches = 0;
+ clc->num_thread_switches = 0;
+ clc->num_fpu_switches = 0;
+
+ for (size_t i = 0; i < util::size(clc->perf_counters); i++) {
+ clc->perf_counters[i] = 0;
+ }
+ }
+
+}
diff --git a/libraries/libmesosphere/source/kern_main.cpp b/libraries/libmesosphere/source/kern_main.cpp
index da4c7de80..0906fe3fc 100644
--- a/libraries/libmesosphere/source/kern_main.cpp
+++ b/libraries/libmesosphere/source/kern_main.cpp
@@ -18,7 +18,14 @@
namespace ams::kern {
NORETURN void HorizonKernelMain(s32 core_id) {
+ /* Setup the Core Local Region, and note that we're initializing. */
+ Kernel::Initialize(core_id);
+ Kernel::SetState(Kernel::State::Initializing);
+
+ /* Ensure that all cores get to this point before proceeding. */
cpu::SynchronizeAllCores();
+
+ /* TODO: Implement more of Main() */
while (true) { /* ... */ }
}