diff --git a/libraries/config/board/nintendo/switch/board.mk b/libraries/config/board/nintendo/nx/board.mk
similarity index 60%
rename from libraries/config/board/nintendo/switch/board.mk
rename to libraries/config/board/nintendo/nx/board.mk
index facdf9632..0a7acfca7 100644
--- a/libraries/config/board/nintendo/switch/board.mk
+++ b/libraries/config/board/nintendo/nx/board.mk
@@ -1,4 +1,4 @@
-export ATMOSPHERE_DEFINES  += -DATMOSPHERE_BOARD_NINTENDO_SWITCH -D__SWITCH__
+export ATMOSPHERE_DEFINES  += -DATMOSPHERE_BOARD_NINTENDO_NX -D__SWITCH__
 export ATMOSPHERE_SETTINGS +=
 export ATMOSPHERE_CFLAGS   +=
 export ATMOSPHERE_CXXFLAGS +=
diff --git a/libraries/config/common.mk b/libraries/config/common.mk
index e71dc1500..7e1c84ab3 100644
--- a/libraries/config/common.mk
+++ b/libraries/config/common.mk
@@ -24,11 +24,11 @@ export ATMOSPHERE_ASFLAGS  :=
 
 ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
 export ATMOSPHERE_ARCH_DIR   := arch/arm64
-export ATMOSPHERE_BOARD_DIR  := board/nintendo/switch
+export ATMOSPHERE_BOARD_DIR  := board/nintendo/nx
 export ATMOSPHERE_OS_DIR     := os/horizon
 
 export ATMOSPHERE_ARCH_NAME  := arm64
-export ATMOSPHERE_BOARD_NAME := nintendo_switch
+export ATMOSPHERE_BOARD_NAME := nintendo_nx
 export ATMOSPHERE_OS_NAME    := horizon
 endif
 
diff --git a/libraries/libmesosphere/include/mesosphere.hpp b/libraries/libmesosphere/include/mesosphere.hpp
index 85a4bc3a6..b09ff06aa 100644
--- a/libraries/libmesosphere/include/mesosphere.hpp
+++ b/libraries/libmesosphere/include/mesosphere.hpp
@@ -30,6 +30,7 @@
 /* Core pre-initialization includes. */
 #include <mesosphere/kern_select_cpu.hpp>
 #include <mesosphere/kern_select_system_control.hpp>
+#include <mesosphere/kern_k_target_system.hpp>
 
 /* Initialization headers. */
 #include <mesosphere/init/kern_init_elf.hpp>
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp
index 1ae915f1a..329005051 100644
--- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp
@@ -27,7 +27,7 @@ namespace ams::kern::arch::arm64::cpu {
     #error "Unknown CPU for cache line sizes"
 #endif
 
-#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH)
+#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
     constexpr inline size_t NumCores = 4;
 #else
     #error "Unknown Board for cpu::NumCores"
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp
index 5902b11d4..97900023d 100644
--- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp
@@ -28,7 +28,7 @@ namespace ams::kern::arch::arm64 {
             KInterruptName_PerformanceCounter     = 8,
 
             /* PPIs */
-    #if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH)
+    #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
             KInterruptName_VirtualMaintenance     = 25,
             KInterruptName_HypervisorTimer        = 26,
             KInterruptName_VirtualTimer           = 27,
@@ -38,7 +38,7 @@ namespace ams::kern::arch::arm64 {
             KInterruptName_LegacyNIrq             = 31,
     #endif
 
-    #if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH)
+    #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
             KInterruptName_MemoryController       = 109,
     #endif
         };
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp
index fdf59b815..0975d658d 100644
--- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp
@@ -35,7 +35,7 @@ namespace ams::kern::arch::arm64 {
                 BlockType_L3ContiguousBlock,
                 BlockType_L2Block,
 
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
                 BlockType_L2TegraSmmuBlock,
 #endif
 
@@ -48,14 +48,14 @@ namespace ams::kern::arch::arm64 {
             static_assert(L3BlockSize == PageSize);
             static constexpr size_t ContiguousPageSize = L3ContiguousBlockSize;
 
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
             static constexpr size_t L2TegraSmmuBlockSize = 2 * L2BlockSize;
 #endif
             static constexpr size_t BlockSizes[BlockType_Count] = {
                 [BlockType_L3Block]           = L3BlockSize,
                 [BlockType_L3ContiguousBlock] = L3ContiguousBlockSize,
                 [BlockType_L2Block]           = L2BlockSize,
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
                 [BlockType_L2TegraSmmuBlock]  = L2TegraSmmuBlockSize,
 #endif
                 [BlockType_L2ContiguousBlock] = L2ContiguousBlockSize,
@@ -71,7 +71,7 @@ namespace ams::kern::arch::arm64 {
                     case L3BlockSize:           return BlockType_L3Block;
                     case L3ContiguousBlockSize: return BlockType_L3ContiguousBlock;
                     case L2BlockSize:           return BlockType_L2Block;
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
                     case L2TegraSmmuBlockSize:  return BlockType_L2TegraSmmuBlock;
 #endif
                     case L2ContiguousBlockSize: return BlockType_L2ContiguousBlock;
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp
index 113c4777e..2b5665141 100644
--- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp
@@ -34,43 +34,62 @@ namespace ams::kern::arch::arm64 {
             static constexpr size_t LevelBits = 9;
             static_assert(NumLevels > 0);
 
-            static constexpr size_t AddressBits = (NumLevels - 1) * LevelBits + PageBits;
-            static_assert(AddressBits <= BITSIZEOF(u64));
-            static constexpr size_t AddressSpaceSize = (1ull << AddressBits);
+            template<size_t Offset, size_t Count>
+            static constexpr ALWAYS_INLINE u64 GetBits(u64 value) {
+                return (value >> Offset) & ((1ul << Count) - 1);
+            }
+
+            template<size_t Offset, size_t Count>
+            constexpr ALWAYS_INLINE u64 SelectBits(u64 value) {
+                return value & (((1ul << Count) - 1) << Offset);
+            }
+
+            static constexpr ALWAYS_INLINE uintptr_t GetL0Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 0), LevelBits>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetL1Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 1), LevelBits>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetL2Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 2), LevelBits>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetL3Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 3), LevelBits>(GetInteger(addr)); }
+
+            static constexpr ALWAYS_INLINE uintptr_t GetL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1)>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2)>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3)>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetContiguousL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1) + 4>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetContiguousL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2) + 4>(GetInteger(addr)); }
+            static constexpr ALWAYS_INLINE uintptr_t GetContiguousL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3) + 4>(GetInteger(addr)); }
         private:
             L1PageTableEntry *table;
             bool is_kernel;
             u32  num_entries;
         public:
-            ALWAYS_INLINE KVirtualAddress GetTableEntry(KVirtualAddress table, size_t index) {
+            ALWAYS_INLINE KVirtualAddress GetTableEntry(KVirtualAddress table, size_t index) const {
                 return table + index * sizeof(PageTableEntry);
             }
 
-            ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) {
-                return GetPointer<L1PageTableEntry>(GetTableEntry(KVirtualAddress(this->table), (GetInteger(address) >> (PageBits + LevelBits * 2)) & (this->num_entries - 1)));
+            ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) const {
+                return GetPointer<L1PageTableEntry>(GetTableEntry(KVirtualAddress(this->table), GetL1Index(address) & (this->num_entries - 1)));
             }
 
-            ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) {
-                return GetPointer<L2PageTableEntry>(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 1)) & ((1ul << LevelBits) - 1)));
+            ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) const {
+                return GetPointer<L2PageTableEntry>(GetTableEntry(table, GetL2Index(address)));
             }
 
-            ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KProcessAddress address) {
+            ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KProcessAddress address) const {
                 return GetL2EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
             }
 
-            ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) {
-                return GetPointer<L3PageTableEntry>(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 0)) & ((1ul << LevelBits) - 1)));
+            ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) const {
+                return GetPointer<L3PageTableEntry>(GetTableEntry(table, GetL3Index(address)));
             }
 
-            ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KProcessAddress address) {
+            ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KProcessAddress address) const {
                 return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
             }
         public:
             constexpr KPageTableImpl() : table(), is_kernel(), num_entries() { /* ... */ }
 
             NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end);
-
             L1PageTableEntry *Finalize();
+
+            bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const;
     };
 
 }
diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp
index c33069681..6596e70fb 100644
--- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp
+++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp
@@ -34,6 +34,10 @@ namespace ams::kern::arch::arm64 {
             Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
                 return this->page_table.MapPages(out_addr, num_pages, alignment, phys_addr, region_start, region_num_pages, state, perm);
             }
+
+            bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
+                return this->page_table.GetPhysicalAddress(out, address);
+            }
     };
 
 }
diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp
similarity index 89%
rename from libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp
rename to libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp
index 3572d0897..e14c73474 100644
--- a/libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp
+++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp
@@ -16,7 +16,7 @@
 #pragma once
 #include <mesosphere/kern_common.hpp>
 
-namespace ams::kern {
+namespace ams::kern::board::nintendo::nx {
 
     class KSystemControl {
         public:
@@ -37,14 +37,16 @@ namespace ams::kern {
             };
         public:
             /* Initialization. */
-            static NOINLINE void Initialize();
+            static NOINLINE void InitializePhase1();
+            static NOINLINE void InitializePhase2();
             static NOINLINE u32 GetInitialProcessBinaryPool();
 
             /* Randomness. */
             static void GenerateRandomBytes(void *dst, size_t size);
             static u64  GenerateRandomRange(u64 min, u64 max);
 
-            /* Panic. */
+            /* Power management. */
+            static void SleepSystem();
             static NORETURN void StopSystem();
     };
 
diff --git a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp
index bb4d4e988..85a707904 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp
@@ -32,7 +32,7 @@ namespace ams::kern {
 
 #ifndef MESOSPHERE_DEBUG_LOG_SELECTED
 
-    #ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+    #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
         #define MESOSPHERE_DEBUG_LOG_USE_UART_C
     #else
         #error "Unknown board for Default Debug Log Source"
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp
index aceefcd8e..e07ce69eb 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp
@@ -15,12 +15,12 @@
  */
 #pragma once
 
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+#ifdef ATMOSPHERE_ARCH_ARM64
     #include <mesosphere/arch/arm64/kern_k_exception_context.hpp>
 
     namespace ams::kern {
         using ams::kern::arch::arm64::KExceptionContext;
     }
 #else
-    #error "Unknown board for KExceptionContext"
+    #error "Unknown architecture for KExceptionContext"
 #endif
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp
index f2a3c3053..68f5ab34a 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp
@@ -196,6 +196,10 @@ namespace ams::kern {
 
             NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
         public:
+            bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const {
+                return this->GetImpl().GetPhysicalAddress(out, virt_addr);
+            }
+
             Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
                 return this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm);
             }
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp
index 123595b4c..2134f830f 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp
@@ -15,11 +15,10 @@
  */
 #pragma once
 #include <mesosphere/kern_common.hpp>
+#include <mesosphere/kern_select_system_control.hpp>
 
 namespace ams::kern {
 
-    class KSystemControl;
-
     class KTargetSystem {
         private:
             friend class KSystemControl;
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread_context.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread_context.hpp
index a675d5184..25df4ae70 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_thread_context.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread_context.hpp
@@ -15,12 +15,12 @@
  */
 #pragma once
 
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+#ifdef ATMOSPHERE_ARCH_ARM64
     #include <mesosphere/arch/arm64/kern_k_thread_context.hpp>
 
     namespace ams::kern {
         using ams::kern::arch::arm64::KThreadContext;
     }
 #else
-    #error "Unknown board for KThreadContext"
+    #error "Unknown architecture for KThreadContext"
 #endif
diff --git a/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp b/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp
index 75c0a4002..5d4890d67 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp
@@ -15,10 +15,14 @@
  */
 #pragma once
 #include <mesosphere/kern_common.hpp>
-#include <mesosphere/kern_k_target_system.hpp>
 
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
-    #include <mesosphere/board/nintendo/switch/kern_k_system_control.hpp>
+#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
+    #include <mesosphere/board/nintendo/nx/kern_k_system_control.hpp>
+
+    namespace ams::kern {
+        using ams::kern::board::nintendo::nx::KSystemControl;
+    }
+
 #else
     #error "Unknown board for KSystemControl"
 #endif
diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp
index a97266d3c..368c0299d 100644
--- a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp
+++ b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp
@@ -20,11 +20,55 @@ namespace ams::kern::arch::arm64 {
     void KPageTableImpl::InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end) {
         this->table       = static_cast<L1PageTableEntry *>(tb);
         this->is_kernel   = true;
-        this->num_entries = util::AlignUp(end - start, AddressSpaceSize) / AddressSpaceSize;
+        this->num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize;
     }
 
     L1PageTableEntry *KPageTableImpl::Finalize() {
         return this->table;
     }
 
+    bool KPageTableImpl::GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
+        /* Validate that we can read the actual entry. */
+        const size_t l0_index = GetL0Index(address);
+        const size_t l1_index = GetL1Index(address);
+        if (this->is_kernel) {
+            /* Kernel entries must be accessed via TTBR1. */
+            if ((l0_index != MaxPageTableEntries - 1) || (l1_index < MaxPageTableEntries - this->num_entries)) {
+                return false;
+            }
+        } else {
+            /* User entries must be accessed with TTBR0. */
+            if ((l0_index != 0) || l1_index >= this->num_entries) {
+                return false;
+            }
+        }
+
+        /* Try to get from l1 table. */
+        const L1PageTableEntry *l1_entry = this->GetL1Entry(address);
+        if (l1_entry->IsBlock()) {
+            *out = l1_entry->GetBlock() + GetL1Offset(address);
+            return true;
+        } else if (!l1_entry->IsTable()) {
+            return false;
+        }
+
+        /* Try to get from l2 table. */
+        const L2PageTableEntry *l2_entry = this->GetL2Entry(l1_entry, address);
+        if (l2_entry->IsBlock()) {
+            *out = l2_entry->GetBlock() + GetL2Offset(address);
+            return true;
+        } else if (!l2_entry->IsTable()) {
+            return false;
+        }
+
+        /* Try to get from l3 table. */
+        const L3PageTableEntry *l3_entry = this->GetL3Entry(l2_entry, address);
+        if (l3_entry->IsBlock()) {
+            *out = l3_entry->GetBlock() + GetL3Offset(address);
+            return true;
+        }
+
+        return false;
+    }
+
 }
diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp
new file mode 100644
index 000000000..3846b1752
--- /dev/null
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#include <mesosphere.hpp>
+#include "kern_k_sleep_manager.hpp"
+#include "kern_secure_monitor.hpp"
+
+namespace ams::kern::board::nintendo::nx {
+
+    namespace {
+
+        /* Struct representing registers saved on wake/sleep. */
+        class SavedSystemRegisters {
+            private:
+                u64 ttbr0_el1;
+                u64 tcr_el1;
+                u64 elr_el1;
+                u64 sp_el0;
+                u64 spsr_el1;
+                u64 daif;
+                u64 cpacr_el1;
+                u64 vbar_el1;
+                u64 csselr_el1;
+                u64 cntp_ctl_el0;
+                u64 cntp_cval_el0;
+                u64 cntkctl_el1;
+                u64 tpidr_el0;
+                u64 tpidrro_el0;
+                u64 mdscr_el1;
+                u64 contextidr_el1;
+                u64 dbgwcrN_el1[16];
+                u64 dbgwvrN_el1[16];
+                u64 dbgbcrN_el1[16];
+                u64 dbgbvrN_el1[16];
+                u64 pmccfiltr_el0;
+                u64 pmccntr_el0;
+                u64 pmcntenset_el0;
+                u64 pmcr_el0;
+                u64 pmevcntrN_el0[31];
+                u64 pmevtyperN_el0[31];
+                u64 pmcntenset_el1;
+                u64 pmovsset_el0;
+                u64 pmselr_el0;
+                u64 pmuserenr_el0;
+            public:
+                void Save();
+                void Restore() const;
+        };
+
+        constexpr s32 SleepManagerThreadPriority = 2;
+
+        /* Globals for sleep/wake. */
+        u64 g_sleep_target_cores;
+        KLightLock g_request_lock;
+        KLightLock g_cv_lock;
+        KLightConditionVariable g_cv;
+        KPhysicalAddress g_sleep_buffer_phys_addrs[cpu::NumCores];
+        alignas(16) u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)];
+        SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {};
+
+    }
+
+    void KSleepManager::Initialize() {
+        /* Create a sleep manager thread for each core. */
+        for (size_t core_id = 0; core_id < cpu::NumCores; core_id++) {
+            /* Reserve a thread from the system limit. */
+            MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_ThreadCountMax, 1));
+
+            /* Create a new thread. */
+            KThread *new_thread = KThread::Create();
+            MESOSPHERE_ABORT_UNLESS(new_thread != nullptr);
+
+            /* Launch the new thread. */
+            MESOSPHERE_R_ABORT_UNLESS(KThread::InitializeKernelThread(new_thread, KSleepManager::ProcessRequests, reinterpret_cast<uintptr_t>(g_sleep_buffers[core_id]), SleepManagerThreadPriority, static_cast<s32>(core_id)));
+
+            /* Register the new thread. */
+            KThread::Register(new_thread);
+
+            /* Run the thread. */
+            new_thread->Run();
+        }
+    }
+
+    void KSleepManager::SleepSystem() {
+        /* Ensure device mappings are not modified during sleep. */
+        MESOSPHERE_TODO("KDevicePageTable::Lock();");
+        ON_SCOPE_EXIT { MESOSPHERE_TODO("KDevicePageTable::Unlock();"); };
+
+        /* Request that the system sleep. */
+        {
+            KScopedLightLock lk(g_request_lock);
+
+            /* Signal the manager to sleep on all cores. */
+            {
+                KScopedLightLock lk(g_cv_lock);
+                MESOSPHERE_ABORT_UNLESS(g_sleep_target_cores == 0);
+
+                g_sleep_target_cores = (1ul << (cpu::NumCores - 1));
+                g_cv.Broadcast();
+
+                while (g_sleep_target_cores != 0) {
+                    g_cv.Wait(std::addressof(g_cv_lock));
+                }
+            }
+        }
+    }
+
+    void KSleepManager::ProcessRequests(uintptr_t buffer) {
+        const s32 core_id = GetCurrentCoreId();
+        KPhysicalAddress resume_entry_phys_addr = Null<KPhysicalAddress>;
+
+        /* Get the physical addresses we'll need. */
+        {
+            MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(g_sleep_buffer_phys_addrs[core_id]), KProcessAddress(buffer)));
+            MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(resume_entry_phys_addr), KProcessAddress(&::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry)));
+
+        }
+        const KPhysicalAddress sleep_buffer_phys_addr = g_sleep_buffer_phys_addrs[core_id];
+        const u64 target_core_mask = (1ul << core_id);
+
+        /* Loop, processing sleep when requested. */
+        while (true) {
+            /* Wait for a request. */
+            {
+                KScopedLightLock lk(g_cv_lock);
+                while (!(g_sleep_target_cores & target_core_mask)) {
+                    g_cv.Wait(std::addressof(g_cv_lock));
+                }
+            }
+
+            MESOSPHERE_TODO("Implement Sleep/Wake");
+            (void)(g_sleep_system_registers[core_id]);
+            (void)(sleep_buffer_phys_addr);
+
+            /* Signal request completed. */
+            {
+                KScopedLightLock lk(g_cv_lock);
+                g_sleep_target_cores &= ~target_core_mask;
+                if (g_sleep_target_cores == 0) {
+                    g_cv.Broadcast();
+                }
+            }
+        }
+    }
+
+}
diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp
new file mode 100644
index 000000000..1cc500c4d
--- /dev/null
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.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 <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+#include <mesosphere.hpp>
+
+namespace ams::kern::board::nintendo::nx {
+
+    class KSleepManager {
+        private:
+            static void CpuSleepHandler(uintptr_t arg, uintptr_t entry);
+            static void ResumeEntry(uintptr_t arg);
+
+            static void ProcessRequests(uintptr_t buffer);
+        public:
+            static void Initialize();
+            static void SleepSystem();
+    };
+
+
+}
\ No newline at end of file
diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager_asm.s b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager_asm.s
new file mode 100644
index 000000000..1c4a014cd
--- /dev/null
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager_asm.s
@@ -0,0 +1,23 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry(uintptr_t arg) */
+.section    .text._ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, "ax", %progbits
+.global     _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm
+.type       _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function
+_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
+    /* TODO: Implement a real function here. */
+    brk 1000
\ No newline at end of file
diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
similarity index 89%
rename from libraries/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp
rename to libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
index 4e653159d..c0c6cd808 100644
--- a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
@@ -15,14 +15,20 @@
  */
 #include <mesosphere.hpp>
 #include "kern_secure_monitor.hpp"
+#include "kern_k_sleep_manager.hpp"
 
-namespace ams::kern {
+namespace ams::kern::board::nintendo::nx {
 
     namespace {
 
         /* Global variables for panic. */
         bool g_call_smc_on_panic;
 
+        /* Global variables for secure memory. */
+        constexpr size_t SecureAppletReservedMemorySize = 4_MB;
+        KVirtualAddress g_secure_applet_memory_address;
+
+
         /* Global variables for randomness. */
         /* Nintendo uses std::mt19937_t for randomness. */
         /* To save space (and because mt19337_t isn't secure anyway), */
@@ -195,7 +201,7 @@ namespace ams::kern {
     }
 
     /* System Initialization. */
-    void KSystemControl::Initialize() {
+    void KSystemControl::InitializePhase1() {
         /* Set IsDebugMode. */
         {
             KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
@@ -250,6 +256,21 @@ namespace ams::kern {
         }
     }
 
+    void KSystemControl::InitializePhase2() {
+        /* Initialize the sleep manager. */
+        KSleepManager::Initialize();
+
+        /* Reserve secure applet memory. */
+        {
+            MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null<KVirtualAddress>);
+            MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletReservedMemorySize));
+
+            constexpr auto SecureAppletAllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
+            g_secure_applet_memory_address = Kernel::GetMemoryManager().AllocateContinuous(SecureAppletReservedMemorySize / PageSize, 1, SecureAppletAllocateOption);
+            MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>);
+        }
+    }
+
     u32 KSystemControl::GetInitialProcessBinaryPool() {
         return KMemoryManager::Pool_Application;
     }
@@ -274,6 +295,11 @@ namespace ams::kern {
         return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
     }
 
+    void KSystemControl::SleepSystem() {
+        MESOSPHERE_LOG("SleepSystem() was called\n");
+        KSleepManager::SleepSystem();
+    }
+
     void KSystemControl::StopSystem() {
         if (g_call_smc_on_panic) {
             /* Display a panic screen via secure monitor. */
diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp
similarity index 99%
rename from libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp
rename to libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp
index 7c49443d6..d3797d7ea 100644
--- a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp
@@ -16,7 +16,7 @@
 #include <mesosphere.hpp>
 #include "kern_secure_monitor.hpp"
 
-namespace ams::kern::smc {
+namespace ams::kern::board::nintendo::nx::smc {
 
     namespace {
 
diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp
similarity index 98%
rename from libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp
rename to libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp
index 14c1fc38e..dcf1c4dca 100644
--- a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp
@@ -16,7 +16,7 @@
 #pragma once
 #include <mesosphere.hpp>
 
-namespace ams::kern::smc {
+namespace ams::kern::board::nintendo::nx::smc {
 
     /* Types. */
     enum MemorySize {
diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp
similarity index 98%
rename from libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp
rename to libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp
index 8985447cf..e90cbc70f 100644
--- a/libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp
+++ b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp
@@ -14,7 +14,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 #include <mesosphere.hpp>
-#include "../../../kern_debug_log_impl.hpp"
+#include "kern_debug_log_impl.hpp"
 
 namespace ams::kern {
 
diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_memory_layout.board.nintendo_switch.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp
similarity index 100%
rename from libraries/libmesosphere/source/board/nintendo/switch/kern_k_memory_layout.board.nintendo_switch.cpp
rename to libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp
diff --git a/libraries/libmesosphere/source/kern_main.cpp b/libraries/libmesosphere/source/kern_main.cpp
index bafa88c08..9d06110a5 100644
--- a/libraries/libmesosphere/source/kern_main.cpp
+++ b/libraries/libmesosphere/source/kern_main.cpp
@@ -46,8 +46,8 @@ namespace ams::kern {
         });
 
         if (core_id == 0) {
-            /* Initialize KSystemControl. */
-            KSystemControl::Initialize();
+            /* Initialize the carveout and the system resource limit. */
+            KSystemControl::InitializePhase1();
 
             /* Initialize the memory manager and the KPageBuffer slabheap. */
             {
@@ -107,9 +107,11 @@ namespace ams::kern {
 
         /* Perform more core-0 specific initialization. */
         if (core_id == 0) {
+            /* Initialize the exit worker manager, so that threads and processes may exit cleanly. */
             Kernel::GetWorkerTaskManager(KWorkerTaskManager::WorkerType_Exit).Initialize(KWorkerTaskManager::WorkerType_Exit, KWorkerTaskManager::ExitWorkerPriority);
 
-            MESOSPHERE_TODO("KSystemControl::InitializeSleepManagerAndAppletSecureMemory();");
+            /* Setup so that we may sleep later, and reserve memory for secure applets. */
+            KSystemControl::InitializePhase2();
 
             MESOSPHERE_TODO("KDeviceAddressSpace::Initialize();");
 
diff --git a/libraries/libvapours/include/vapours/includes.hpp b/libraries/libvapours/include/vapours/includes.hpp
index 7e1bc682b..64ac45ee2 100644
--- a/libraries/libvapours/include/vapours/includes.hpp
+++ b/libraries/libvapours/include/vapours/includes.hpp
@@ -52,7 +52,7 @@
 
 #endif /* ATMOSPHERE_IS_STRATOSPHERE */
 
-#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
+#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
 
 #ifdef ATMOSPHERE_IS_STRATOSPHERE
 
@@ -70,7 +70,7 @@
 
 #error "Unsupported board"
 
-#endif /* ATMOSPHERE_BOARD_NINTENDO_SWITCH */
+#endif /* ATMOSPHERE_BOARD_NINTENDO_NX */
 
 /* Atmosphere meta. */
 #include "ams_version.h"
diff --git a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp
similarity index 97%
rename from libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp
rename to libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp
index f1175d773..fb289dd83 100644
--- a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp
+++ b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp
@@ -16,7 +16,7 @@
 #pragma once
 #include <vapours/svc/svc_types_common.hpp>
 
-namespace ams::svc::board::nintendo_switch {
+namespace ams::svc::board::nintendo::nx {
 
     enum DeviceName {
         DeviceName_Afi        = 0,
diff --git a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp
similarity index 94%
rename from libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp
rename to libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp
index 55d95f04e..8b270b125 100644
--- a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp
+++ b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp
@@ -16,7 +16,7 @@
 #pragma once
 #include <vapours/svc/svc_types_common.hpp>
 
-namespace ams::svc::board::nintendo_switch {
+namespace ams::svc::board::nintendo::nx {
 
     constexpr inline const s64 TicksPerSecond = 19'200'000;
 
diff --git a/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp b/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp
index 190350676..31e91b351 100644
--- a/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp
+++ b/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp
@@ -17,11 +17,11 @@
 #pragma once
 #include "svc_common.hpp"
 
-#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH)
+#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
 
-    #include "board/nintendo/switch/svc_device_name.hpp"
+    #include "board/nintendo/nx/svc_device_name.hpp"
     namespace ams::svc {
-        using namespace ams::svc::board::nintendo_switch;
+        using namespace ams::svc::board::nintendo::nx;
     }
 
 #else
diff --git a/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp b/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp
index c7bba8105..5ab60ee5d 100644
--- a/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp
+++ b/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp
@@ -17,11 +17,11 @@
 #pragma once
 #include "svc_common.hpp"
 
-#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH)
+#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
 
-    #include "board/nintendo/switch/svc_hardware_constants.hpp"
+    #include "board/nintendo/nx/svc_hardware_constants.hpp"
     namespace ams::svc {
-        using namespace ams::svc::board::nintendo_switch;
+        using namespace ams::svc::board::nintendo::nx;
     }
 
 #else