diff --git a/thermosphere/src/core_ctx.h b/thermosphere/src/core_ctx.h
deleted file mode 100644
index 54a3120ff..000000000
--- a/thermosphere/src/core_ctx.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2019 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 "utils.h"
-
-struct ExceptionStackFrame;
-typedef struct ALIGN(64) CoreCtx {
- // Most likely only just read (assume cache line size of at most 64 bytes):
-
- u64 kernelArgument; // @0x08
- uintptr_t kernelEntrypoint; // @0x10
- u32 coreId; // @0x18
- bool isBootCore; // @0x1D
- bool warmboot; // @0x1E
-
- // Debug features
- bool wasPaused; // @0x1F
- uintptr_t steppingRangeStartAddr; // @0x20
- uintptr_t steppingRangeEndAddr; // @0x28
-
- // Most likely written to:
-
- ALIGN(64) struct ExceptionStackFrame *guestFrame; // @0x40
-
- // Timer stuff
- u64 totalTimeInHypervisor; // @0x50. cntvoff_el2 is updated to that value.
- u64 emulPtimerCval; // @0x58. When setting cntp_cval_el0 and on interrupt
-} CoreCtx;
-
-/*static_assert(offsetof(CoreCtx, warmboot) == 0x1E, "Wrong definition for CoreCtx");
-static_assert(offsetof(CoreCtx, emulPtimerCval) == 0x58, "Wrong definition for CoreCtx");
-static_assert(offsetof(CoreCtx, executedFunctionSync) == 0x78, "Wrong definition for CoreCtx");
-static_assert(offsetof(CoreCtx, setWayCounter) == 0x7C, "Wrong definition for CoreCtx");*/
-
-extern CoreCtx g_coreCtxs[4];
-register CoreCtx *currentCoreCtx asm("x18");
-
-void coreCtxInit(u32 coreId, bool isBootCore, u64 argument);
-
-void setCurrentCoreActive(void);
-u32 getActiveCoreMask(void);
diff --git a/thermosphere/src/hvisor_core_context.cpp b/thermosphere/src/hvisor_core_context.cpp
new file mode 100644
index 000000000..08038f288
--- /dev/null
+++ b/thermosphere/src/hvisor_core_context.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019-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 "hvisor_core_context.hpp"
+#include "cpu/hvisor_cpu_instructions.hpp"
+
+namespace ams::hvisor {
+
+ std::array CoreContext::instances{};
+ std::atomic CoreContext::activeCoreMask{};
+ bool CoreContext::coldboot = true;
+
+ void CoreContext::InitializeCoreInstance(u32 coreId, bool isBootCore, u64 argument)
+ {
+ CoreContext &instance = instances[coreId];
+ instance.m_coreId = coreId;
+ instance.m_bootCore = isBootCore;
+ instance.m_kernelArgument = argument;
+ if (isBootCore && instance.m_kernelEntrypoint == 0) {
+ instance.m_kernelEntrypoint = initialKernelEntrypoint;
+ }
+ currentCoreCtx = &instance;
+ cpu::dmb();
+ }
+}
diff --git a/thermosphere/src/hvisor_core_context.hpp b/thermosphere/src/hvisor_core_context.hpp
new file mode 100644
index 000000000..84763c621
--- /dev/null
+++ b/thermosphere/src/hvisor_core_context.hpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019-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 "defines.hpp"
+
+namespace ams::hvisor {
+
+ struct ExceptionStackFrame;
+ class CoreContext;
+
+ register CoreContext *currentCoreCtx asm("x18");
+
+ class alignas(64) CoreContext final {
+ // This should be 64-byte big
+ NON_COPYABLE(CoreContext);
+ NON_MOVEABLE(CoreContext);
+ private:
+ static std::array instances;
+ static std::atomic activeCoreMask;
+ static bool coldboot; // "coldboot" to be 'true' on init & thus not in BSS
+
+ // start.s
+ static uintptr_t initialKernelEntrypoint;
+
+ private:
+ ExceptionStackFrame *m_guestFrame = nullptr;
+
+ u64 m_kernelArgument = 0;
+ uintptr_t m_kernelEntrypoint = 0;
+
+ u32 m_coreId = 0;
+ bool m_bootCore = false;
+
+ // Debug features
+ bool m_wasPaused = false;
+ uintptr_t m_steppingRangeStartAddr = 0;
+ uintptr_t m_steppingRangeEndAddr = 0;
+
+ // Timer stuff
+ u64 m_totalTimeInHypervisor = 0;
+ u64 m_emulPtimerCval = 0;
+
+ private:
+ constexpr CoreContext() = default;
+
+ public:
+ static void InitializeCoreInstance(u32 coreId, bool isBootCore, u64 argument);
+
+ static CoreContext &GetInstanceFor(u32 coreId) { return instances[coreId]; }
+ static u32 GetActiveCoreMask() { return activeCoreMask.load(); }
+ static u32 SetCurrentCoreActive()
+ {
+ activeCoreMask |= BIT(currentCoreCtx->m_coreId);
+ }
+ static bool IsColdboot() { return coldboot; }
+
+ public:
+ constexpr ExceptionStackFrame *GetGuestFrame() const { return m_guestFrame; }
+ constexpr void SetGuestFrame(ExceptionStackFrame *frame) { m_guestFrame = frame; }
+
+ constexpr u64 GetKernelArgument() const { return m_kernelArgument; }
+
+ constexpr u64 GetKernelEntrypoint() const { return m_kernelEntrypoint; }
+
+ constexpr u32 GetCoreId() const { return m_coreId; }
+
+ constexpr u64 SetWarmboot(uintptr_t ep)
+ {
+ // No race possible, only possible transition is 1->0 and we only really check IsColdboot() at init time
+ // And CPU_SUSPEND should only be called with only one core left.
+ coldboot = false;
+ m_kernelEntrypoint = ep;
+ }
+
+ constexpr bool WasPaused() const { return m_wasPaused; }
+ constexpr void SetPausedFlag(bool wasPaused) { m_wasPaused = wasPaused; }
+
+ constexpr auto GetSteppingRange() const
+ {
+ return std::tuple{m_steppingRangeStartAddr, m_steppingRangeEndAddr};
+ }
+ constexpr void SetSteppingRange(uintptr_t startAddr, uintptr_t endAddr)
+ {
+ m_steppingRangeStartAddr = startAddr;
+ m_steppingRangeEndAddr = endAddr;
+ }
+
+ constexpr u64 GetTotalTimeInHypervisor() const { return m_totalTimeInHypervisor; }
+ constexpr void IncrementTotalTimeInHypervisor(u64 timeDelta) { m_totalTimeInHypervisor += timeDelta; }
+
+ constexpr u64 GetEmulPtimerCval() const { return m_emulPtimerCval; }
+ constexpr void SetEmulPtimerCval(u64 cval) { m_emulPtimerCval = cval; }
+ };
+}
diff --git a/thermosphere/src/start.s b/thermosphere/src/start.s
index b276b23ae..a10f4c2ac 100644
--- a/thermosphere/src/start.s
+++ b/thermosphere/src/start.s
@@ -25,8 +25,8 @@ _start:
b start
b start2
-.global g_initialKernelEntrypoint
-g_initialKernelEntrypoint:
+.global _ZN3ams6hvisor11CoreContext23initialKernelEntrypointE
+_ZN3ams6hvisor11CoreContext23initialKernelEntrypointE:
.quad 0
start: