diff --git a/libmesosphere/include/mesosphere.hpp b/libmesosphere/include/mesosphere.hpp
index 77e798d9..0da2f63e 100644
--- a/libmesosphere/include/mesosphere.hpp
+++ b/libmesosphere/include/mesosphere.hpp
@@ -23,6 +23,13 @@
/* Primitive types. */
#include "mesosphere/kern_k_typed_address.hpp"
+#include "mesosphere/kern_initial_process.hpp"
+
+/* Initialization headers. */
+#include "mesosphere/init/kern_init_elf.hpp"
+#include "mesosphere/init/kern_init_layout.hpp"
+#include "mesosphere/init/kern_init_page_table_select.hpp"
/* Core functionality. */
+#include "mesosphere/kern_select_interrupts.hpp"
#include "mesosphere/kern_select_k_system_control.hpp"
diff --git a/libmesosphere/include/mesosphere/arch/arm64/init/kern_init_elf64.hpp b/libmesosphere/include/mesosphere/arch/arm64/init/kern_init_elf64.hpp
new file mode 100644
index 00000000..33ef192f
--- /dev/null
+++ b/libmesosphere/include/mesosphere/arch/arm64/init/kern_init_elf64.hpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+/*
+From musl include/elf.h
+
+Copyright © 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#pragma once
+#include
+
+namespace ams::kern::init::Elf::Elf64 {
+
+ /* Type declarations required to perform relocations */
+ using Half = u16;
+ using Word = u32;
+ using Sword = s32;
+ using Xword = u64;
+ using SXword = s64;
+
+ using Addr = u64;
+ using Off = u64;
+
+ class Dyn {
+ private:
+ SXword tag;
+ union {
+ Xword value;
+ Addr ptr;
+ };
+ public:
+ constexpr ALWAYS_INLINE SXword GetTag() const {
+ return this->tag;
+ }
+
+ constexpr ALWAYS_INLINE Xword GetValue() const {
+ return this->value;
+ }
+
+ constexpr ALWAYS_INLINE Addr GetPtr() const {
+ return this->ptr;
+ }
+ };
+
+ class Rel {
+ private:
+ Addr offset;
+ Xword info;
+ public:
+ constexpr ALWAYS_INLINE Addr GetOffset() const {
+ return this->offset;
+ }
+
+ constexpr ALWAYS_INLINE Xword GetSym() const {
+ return this->info >> 32;
+ }
+
+ constexpr ALWAYS_INLINE Xword GetType() const {
+ return this->info & 0xFFFFFFFF;
+ }
+ };
+
+ class Rela {
+ private:
+ Addr offset;
+ Xword info;
+ SXword addend;
+ public:
+ constexpr ALWAYS_INLINE Addr GetOffset() const {
+ return this->offset;
+ }
+
+ constexpr ALWAYS_INLINE Xword GetSym() const {
+ return this->info >> 32;
+ }
+
+ constexpr ALWAYS_INLINE Xword GetType() const {
+ return this->info & 0xFFFFFFFF;
+ }
+
+ constexpr ALWAYS_INLINE SXword GetAddend() const {
+ return this->addend;
+ }
+ };
+
+ enum DynamicTag {
+ DT_NULL = 0,
+ DT_RELA = 7,
+ DT_RELAENT = 9,
+ DT_REL = 17,
+ DT_RELENT = 19,
+
+ DT_RELACOUNT = 0x6ffffff9,
+ DT_RELCOUNT = 0x6ffffffa
+ };
+
+ enum RelocationType {
+ R_AARCH64_RELATIVE = 0x403,
+ };
+
+ /* API to apply relocations or call init array. */
+ void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic);
+ void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end);
+
+}
\ No newline at end of file
diff --git a/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp b/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp
new file mode 100644
index 00000000..2d2c6fc3
--- /dev/null
+++ b/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+/*
+From musl include/elf.h
+
+Copyright © 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#pragma once
+#include
+#include
+#include
+#include "../kern_hardware_registers.hpp"
+
+namespace ams::kern::init {
+
+ constexpr size_t PageSize = 0x1000;
+ constexpr size_t L1BlockSize = 0x40000000;
+ constexpr size_t L2BlockSize = 0x200000;
+ constexpr size_t L2ContiguousBlockSize = 0x10 * L2BlockSize;
+ constexpr size_t L3BlockSize = 0x1000;
+ constexpr size_t L3ContiguousBlockSize = 0x10 * L3BlockSize;
+
+ class PageTableEntry {
+ public:
+ enum Permission : u64 {
+ Permission_KernelRWX = ((0ul << 53) | (1ul << 54) | (0ul << 6)),
+ Permission_KernelRX = ((0ul << 53) | (1ul << 54) | (2ul << 6)),
+ Permission_KernelR = ((1ul << 53) | (1ul << 54) | (2ul << 6)),
+ Permission_KernelRW = ((1ul << 53) | (1ul << 54) | (0ul << 6)),
+
+ Permission_UserRX = ((1ul << 53) | (0ul << 54) | (3ul << 6)),
+ Permission_UserR = ((1ul << 53) | (1ul << 54) | (3ul << 6)),
+ Permission_UserRW = ((1ul << 53) | (1ul << 54) | (1ul << 6)),
+ };
+
+ enum Shareable : u64 {
+ Shareable_NonShareable = (0 << 8),
+ Shareable_OuterShareable = (2 << 8),
+ Shareable_InnerShareable = (3 << 8),
+ };
+
+ /* Official attributes are: */
+ /* 0x00, 0x04, 0xFF, 0x44. 4-7 are unused. */
+ enum PageAttribute : u64 {
+ PageAttribute_Device_nGnRnE = (0 << 2),
+ PageAttribute_Device_nGnRE = (1 << 2),
+ PageAttribute_NormalMemory = (2 << 2),
+ PageAttribute_NormalMemoryNotCacheable = (3 << 2),
+ };
+
+ enum AccessFlag : u64 {
+ AccessFlag_NotAccessed = (0 << 10),
+ AccessFlag_Accessed = (1 << 10),
+ };
+ protected:
+ u64 attributes;
+ public:
+ /* Take in a raw attribute. */
+ constexpr ALWAYS_INLINE PageTableEntry(u64 attr) : attributes(attr) { /* ... */ }
+
+ /* Extend a previous attribute. */
+ constexpr ALWAYS_INLINE PageTableEntry(const PageTableEntry &rhs, u64 new_attr) : attributes(rhs.attributes | new_attr) { /* ... */ }
+
+ /* Construct a new attribute. */
+ constexpr ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share)
+ : attributes(static_cast(perm) | static_cast(AccessFlag_Accessed) | static_cast(p_a) | static_cast(share))
+ {
+ /* ... */
+ }
+ protected:
+ constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const {
+ return (this->attributes >> offset) & ((1 << count) - 1);
+ }
+
+ constexpr ALWAYS_INLINE u64 SelectBits(size_t offset, size_t count) const {
+ return this->attributes & (((1 << count) - 1) << offset);
+ }
+ public:
+ constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; }
+ constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
+ constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
+ constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast(this->GetBits(10, 1)); }
+ constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast(this->GetBits(8, 2)); }
+ constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast(this->GetBits(2, 3)); }
+ constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
+ constexpr ALWAYS_INLINE bool IsBlock() const { return this->GetBits(0, 2) == 0x1; }
+ constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBits(0, 2) == 0x3; }
+ };
+
+ static_assert(sizeof(PageTableEntry) == sizeof(u64));
+
+ constexpr size_t MaxPageTableEntries = PageSize / sizeof(PageTableEntry);
+
+ class L1PageTableEntry : public PageTableEntry {
+ public:
+ constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, bool pxn)
+ : PageTableEntry((0x3ul << 60) | (static_cast(pxn) << 59) | GetInteger(phys_addr) | 0x3)
+ {
+ /* ... */
+ }
+ constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
+ : PageTableEntry(attr, (static_cast(contig) << 52) | GetInteger(phys_addr) | 0x1)
+ {
+ /* ... */
+ }
+
+ constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
+ return this->SelectBits(30, 18);
+ }
+ constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const {
+ return this->SelectBits(12, 36);
+ }
+ };
+
+ class L2PageTableEntry : public PageTableEntry {
+ public:
+ constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, bool pxn)
+ : PageTableEntry((0x3ul << 60) | (static_cast(pxn) << 59) | GetInteger(phys_addr) | 0x3)
+ {
+ /* ... */
+ }
+ constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
+ : PageTableEntry(attr, (static_cast(contig) << 52) | GetInteger(phys_addr) | 0x1)
+ {
+ /* ... */
+ }
+
+ constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
+ return this->SelectBits(21, 27);
+ }
+ constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const {
+ return this->SelectBits(12, 36);
+ }
+ };
+
+ class L3PageTableEntry : public PageTableEntry {
+ public:
+ constexpr ALWAYS_INLINE L3PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
+ : PageTableEntry(attr, (static_cast(contig) << 52) | GetInteger(phys_addr) | 0x1)
+ {
+ /* ... */
+ }
+
+ constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
+ return this->SelectBits(21, 27);
+ }
+ constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const {
+ return this->SelectBits(12, 36);
+ }
+ };
+
+
+ class KInitialPageTable {
+ public:
+ class IPageAllocator {
+ public:
+ virtual KPhysicalAddress Allocate() { return Null; }
+ virtual void Free(KPhysicalAddress phys_addr) { /* Nothing to do here. */ (void)(phys_addr); }
+ };
+ private:
+ KPhysicalAddress l1_table;
+ public:
+ constexpr ALWAYS_INLINE KInitialPageTable(KPhysicalAddress l1) : l1_table(l1) {
+ ClearNewPageTable(this->l1_table);
+ }
+ private:
+ static constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KPhysicalAddress _l1_table, KVirtualAddress address) {
+ L1PageTableEntry *l1_table = reinterpret_cast(GetInteger(_l1_table));
+ return l1_table + ((GetInteger(address) >> 30) & (MaxPageTableEntries - 1));
+ }
+
+ static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address) {
+ L2PageTableEntry *l2_table = reinterpret_cast(GetInteger(entry->GetTable()));
+ return l2_table + ((GetInteger(address) >> 21) & (MaxPageTableEntries - 1));
+ }
+
+ static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address) {
+ L3PageTableEntry *l3_table = reinterpret_cast(GetInteger(entry->GetTable()));
+ return l3_table + ((GetInteger(address) >> 12) & (MaxPageTableEntries - 1));
+ }
+
+ static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
+ /* This Physical Address -> void * conversion is valid, because this is page table code. */
+ /* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
+ std::memset(reinterpret_cast(GetInteger(address)), 0, PageSize);
+ }
+ public:
+ void Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, IPageAllocator &allocator) {
+ /* Ensure that addresses and sizes are page aligned. */
+ MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
+ MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
+ MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize));
+
+ /* Iteratively map pages until the requested region is mapped. */
+ while (size > 0) {
+ L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
+
+ /* Can we make an L1 block? */
+ if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && util::IsAligned(size, L1BlockSize)) {
+ *l1_entry = L1PageTableEntry(phys_addr, attr, false);
+ /* TODO: DataSynchronizationBarrier */
+ virt_addr += L1BlockSize;
+ phys_addr += L1BlockSize;
+ size -= L1BlockSize;
+ continue;
+ }
+
+ /* If we don't already have an L2 table, we need to make a new one. */
+ if (!l1_entry->IsTable()) {
+ KPhysicalAddress new_table = allocator.Allocate();
+ ClearNewPageTable(new_table);
+ *l1_entry = L1PageTableEntry(phys_addr, attr.IsPrivilegedExecuteNever());
+ }
+
+ L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
+
+ /* Can we make a contiguous L2 block? */
+ if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && util::IsAligned(size, L2ContiguousBlockSize)) {
+ for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
+ l2_entry[i] = L2PageTableEntry(phys_addr, attr, true);
+ /* TODO: DataSynchronizationBarrier */
+ virt_addr += L2ContiguousBlockSize;
+ phys_addr += L2ContiguousBlockSize;
+ size -= L2ContiguousBlockSize;
+ }
+ continue;
+ }
+
+ /* Can we make an L2 block? */
+ if (util::IsAligned(GetInteger(virt_addr), L2BlockSize) && util::IsAligned(GetInteger(phys_addr), L2BlockSize) && util::IsAligned(size, L2BlockSize)) {
+ *l2_entry = L2PageTableEntry(phys_addr, attr, false);
+ /* TODO: DataSynchronizationBarrier */
+ virt_addr += L2BlockSize;
+ phys_addr += L2BlockSize;
+ size -= L2BlockSize;
+ continue;
+ }
+
+ /* If we don't already have an L3 table, we need to make a new one. */
+ if (!l2_entry->IsTable()) {
+ KPhysicalAddress new_table = allocator.Allocate();
+ ClearNewPageTable(new_table);
+ *l2_entry = L2PageTableEntry(phys_addr, attr.IsPrivilegedExecuteNever());
+ }
+
+ L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
+
+ /* Can we make a contiguous L3 block? */
+ if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && util::IsAligned(size, L3ContiguousBlockSize)) {
+ for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
+ l3_entry[i] = L3PageTableEntry(phys_addr, attr, true);
+ /* TODO: DataSynchronizationBarrier */
+ virt_addr += L3ContiguousBlockSize;
+ phys_addr += L3ContiguousBlockSize;
+ size -= L3ContiguousBlockSize;
+ }
+ continue;
+ }
+
+ /* Make an L3 block. */
+ *l3_entry = L3PageTableEntry(phys_addr, attr, false);
+ /* TODO: DataSynchronizationBarrier */
+ virt_addr += L3BlockSize;
+ phys_addr += L3BlockSize;
+ size -= L3BlockSize;
+ }
+ }
+
+ bool IsFree(KVirtualAddress virt_addr, size_t size) {
+ /* TODO */
+ return false;
+ }
+
+ void ReprotectFromReadWriteToRead(KVirtualAddress virt_addr, size_t size) {
+ /* TODO */
+ }
+
+ };
+
+}
\ No newline at end of file
diff --git a/libmesosphere/include/mesosphere/arch/arm64/kern_hardware_registers.hpp b/libmesosphere/include/mesosphere/arch/arm64/kern_hardware_registers.hpp
new file mode 100644
index 00000000..74da7387
--- /dev/null
+++ b/libmesosphere/include/mesosphere/arch/arm64/kern_hardware_registers.hpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+/*
+From musl include/elf.h
+
+Copyright © 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#pragma once
+#include
+
+namespace ams::kern::hw {
+
+
+
+}
diff --git a/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp b/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp
index d28a1230..3426f274 100644
--- a/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp
+++ b/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp
@@ -21,6 +21,10 @@ namespace ams::kern {
class KSystemControl {
public:
+ /* Initialization. */
+ static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
+ static bool ShouldIncreaseResourceRegionSize();
+
/* Panic. */
static NORETURN void StopSystem();
};
diff --git a/libmesosphere/include/mesosphere/init/kern_init_elf.hpp b/libmesosphere/include/mesosphere/init/kern_init_elf.hpp
new file mode 100644
index 00000000..2ee1e001
--- /dev/null
+++ b/libmesosphere/include/mesosphere/init/kern_init_elf.hpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018-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
+
+#ifdef ATMOSPHERE_ARCH_ARM64
+
+ #include "../arch/arm64/init/kern_init_elf64.hpp"
+
+#else
+
+ #error "Unknown Architecture"
+
+#endif
+
+namespace ams::kern::init::Elf {
+
+ /* TODO: Anything we want inside this namespace? */
+
+}
\ No newline at end of file
diff --git a/libmesosphere/include/mesosphere/init/kern_init_layout.hpp b/libmesosphere/include/mesosphere/init/kern_init_layout.hpp
new file mode 100644
index 00000000..1e3bfce8
--- /dev/null
+++ b/libmesosphere/include/mesosphere/init/kern_init_layout.hpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-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
+
+namespace ams::kern::init {
+
+ struct KernelLayout {
+ u32 rx_offset;
+ u32 rx_end_offset;
+ u32 ro_offset;
+ u32 ro_end_offset;
+ u32 rw_offset;
+ u32 rw_end_offset;
+ u32 bss_offset;
+ u32 bss_end_offset;
+ u32 ini_end_offset;
+ u32 dynamic_end_offset;
+ u32 init_array_offset;
+ u32 init_array_end_offset;
+ };
+ static_assert(std::is_pod::value);
+ static_assert(sizeof(KernelLayout) == 0x30);
+
+}
\ No newline at end of file
diff --git a/libmesosphere/include/mesosphere/init/kern_init_page_table_select.hpp b/libmesosphere/include/mesosphere/init/kern_init_page_table_select.hpp
new file mode 100644
index 00000000..e0e6b423
--- /dev/null
+++ b/libmesosphere/include/mesosphere/init/kern_init_page_table_select.hpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018-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
+
+#ifdef ATMOSPHERE_ARCH_ARM64
+ #include "../arch/arm64/init/kern_k_init_page_table.hpp"
+#else
+ #error "Unknown architecutre for KInitialPageTable"
+#endif
diff --git a/libmesosphere/include/mesosphere/kern_initial_process.hpp b/libmesosphere/include/mesosphere/kern_initial_process.hpp
new file mode 100644
index 00000000..e901dd4c
--- /dev/null
+++ b/libmesosphere/include/mesosphere/kern_initial_process.hpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018-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 "kern_panic.hpp"
+
+namespace ams::kern {
+
+ constexpr u32 InitialProcessBinaryMagic = util::FourCC<'I','N','I','1'>::Code;
+ constexpr size_t InitialProcessBinarySizeMax = 0xC00000;
+
+ struct InitialProcessBinaryHeader {
+ u32 magic;
+ u32 size;
+ u32 num_processes;
+ u32 reserved;
+ };
+
+}
diff --git a/libmesosphere/include/mesosphere/kern_panic.hpp b/libmesosphere/include/mesosphere/kern_panic.hpp
index 49a6e7b3..27c54cf4 100644
--- a/libmesosphere/include/mesosphere/kern_panic.hpp
+++ b/libmesosphere/include/mesosphere/kern_panic.hpp
@@ -32,7 +32,7 @@ namespace ams::kern {
#ifdef MESOSPHERE_ENABLE_ASSERTIONS
#define MESOSPHERE_ASSERT_IMPL(expr, ...) \
({ \
- if (AMS_UNLIKELY(!expr)) { \
+ if (AMS_UNLIKELY(!(expr))) { \
MESOSPHERE_PANIC(__VA_ARGS__); \
} \
})
@@ -47,7 +47,7 @@ namespace ams::kern {
#define MESOSPHERE_ABORT_UNLESS(expr) \
({ \
- if (AMS_UNLIKELY(!expr)) { \
+ if (AMS_UNLIKELY(!(expr))) { \
MESOSPHERE_PANIC("Abort(): %s", #expr); \
} \
})
diff --git a/libmesosphere/include/mesosphere/kern_select_interrupts.hpp b/libmesosphere/include/mesosphere/kern_select_interrupts.hpp
new file mode 100644
index 00000000..63a5c739
--- /dev/null
+++ b/libmesosphere/include/mesosphere/kern_select_interrupts.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018-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 "kern_panic.hpp"
+
+namespace ams::kern {
+
+ /* TODO: Actually select between architecture-specific interrupt code. */
+
+
+ /* Enable or disable interrupts for the lifetime of an object. */
+ class KScopedInterruptDisable {
+ NON_COPYABLE(KScopedInterruptDisable);
+ NON_MOVEABLE(KScopedInterruptDisable);
+ public:
+ KScopedInterruptDisable();
+ ~KScopedInterruptDisable();
+ };
+
+ class KScopedInterruptEnable {
+ NON_COPYABLE(KScopedInterruptEnable);
+ NON_MOVEABLE(KScopedInterruptEnable);
+ public:
+ KScopedInterruptEnable();
+ ~KScopedInterruptEnable();
+ };
+
+}
diff --git a/libmesosphere/include/mesosphere/kern_select_k_system_control.hpp b/libmesosphere/include/mesosphere/kern_select_k_system_control.hpp
index 56ddc9f6..3c6b5b6d 100644
--- a/libmesosphere/include/mesosphere/kern_select_k_system_control.hpp
+++ b/libmesosphere/include/mesosphere/kern_select_k_system_control.hpp
@@ -19,4 +19,4 @@
#include "board/nintendo/switch/kern_k_system_control.hpp"
#else
#error "Unknown board for KSystemControl"
-#endif
\ No newline at end of file
+#endif
diff --git a/libmesosphere/source/arch/arm64/init/kern_init_elf64.cpp b/libmesosphere/source/arch/arm64/init/kern_init_elf64.cpp
new file mode 100644
index 00000000..8e60b51e
--- /dev/null
+++ b/libmesosphere/source/arch/arm64/init/kern_init_elf64.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+#include
+
+namespace ams::kern::init::Elf::Elf64 {
+
+ /* API to apply relocations or call init array. */
+ void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
+ uintptr_t dyn_rel = 0;
+ uintptr_t dyn_rela = 0;
+ uintptr_t rel_count = 0;
+ uintptr_t rela_count = 0;
+ uintptr_t rel_ent = 0;
+ uintptr_t rela_ent = 0;
+
+ /* Iterate over all tags, identifying important extents. */
+ for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
+ switch (cur_entry->GetTag()) {
+ case DT_REL:
+ dyn_rel = base_address + cur_entry->GetPtr();
+ break;
+ case DT_RELA:
+ dyn_rela = base_address + cur_entry->GetPtr();
+ break;
+ case DT_RELENT:
+ rel_ent = cur_entry->GetValue();
+ break;
+ case DT_RELAENT:
+ rela_ent = cur_entry->GetValue();
+ break;
+ case DT_RELCOUNT:
+ rel_count = cur_entry->GetValue();
+ break;
+ case DT_RELACOUNT:
+ rela_count = cur_entry->GetValue();
+ break;
+ }
+ }
+
+ /* Apply all Rel relocations */
+ for (size_t i = 0; i < rel_count; i++) {
+ const auto &rel = *reinterpret_cast(dyn_rel + rel_ent * i);
+
+ /* Only allow R_AARCH64_RELATIVE relocations. */
+ while (rel.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
+
+ /* Apply the relocation. */
+ Elf64::Addr *target_address = reinterpret_cast(base_address + rel.GetOffset());
+ *target_address += base_address;
+ }
+
+ /* Apply all Rela relocations. */
+ for (size_t i = 0; i < rela_count; i++) {
+ const auto &rela = *reinterpret_cast(dyn_rela + rela_ent * i);
+
+ /* Only allow R_AARCH64_RELATIVE relocations. */
+ while (rela.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
+
+ /* Apply the relocation. */
+ Elf64::Addr *target_address = reinterpret_cast(base_address + rela.GetOffset());
+ *target_address = base_address + rela.GetAddend();
+ }
+ }
+
+ void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
+
+ }
+
+}
\ No newline at end of file
diff --git a/libmesosphere/source/arch/arm64/kern_init_elf64.cpp b/libmesosphere/source/arch/arm64/kern_init_elf64.cpp
new file mode 100644
index 00000000..6f846763
--- /dev/null
+++ b/libmesosphere/source/arch/arm64/kern_init_elf64.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+#include
+
+namespace ams::kern::init::Elf::Elf64 {
+
+ /* API to apply relocations or call init array. */
+ void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
+ uintptr_t dyn_rel = 0;
+ uintptr_t dyn_rela = 0;
+ uintptr_t rel_count = 0;
+ uintptr_t rela_count = 0;
+ uintptr_t rel_ent = 0;
+ uintptr_t rela_ent = 0;
+
+ /* Iterate over all tags, identifying important extents. */
+ for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
+ switch (cur_entry->GetTag()) {
+ case DT_REL:
+ dyn_rel = base_address + cur_entry->GetPtr();
+ break;
+ case DT_RELA:
+ dyn_rela = base_address + cur_entry->GetPtr();
+ break;
+ case DT_RELENT:
+ rel_ent = cur_entry->GetValue();
+ break;
+ case DT_RELAENT:
+ rela_ent = cur_entry->GetValue();
+ break;
+ case DT_RELCOUNT:
+ rel_count = cur_entry->GetValue();
+ break;
+ case DT_RELACOUNT:
+ rela_count = cur_entry->GetValue();
+ break;
+ }
+ }
+
+ /* Apply all Rel relocations */
+ for (size_t i = 0; i < rel_count; i++) {
+ const auto &rel = *reinterpret_cast(dyn_rel + rel_ent * i);
+
+ /* Only allow R_AARCH64_RELATIVE relocations. */
+ while (rel.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
+
+ /* Apply the relocation. */
+ Elf64::Addr *target_address = reinterpret_cast(base_address + rel.GetOffset());
+ *target_address += base_address;
+ }
+
+ /* Apply all Rela relocations. */
+ for (size_t i = 0; i < rela_count; i++) {
+ const auto &rela = *reinterpret_cast(dyn_rela + rela_ent * i);
+
+ /* Only allow R_AARCH64_RELATIVE relocations. */
+ while (rela.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
+
+ /* Apply the relocation. */
+ Elf64::Addr *target_address = reinterpret_cast(base_address + rela.GetOffset());
+ *target_address = base_address + rela.GetAddend();
+ }
+ }
+
+ void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
+ for (uintptr_t cur_entry = init_array_start; cur_entry < init_array_end; cur_entry += sizeof(void *)) {
+ (*(void (**)())(cur_entry))();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp b/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp
index 0bc82900..f5cd9fc7 100644
--- a/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp
+++ b/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp
@@ -18,8 +18,64 @@
namespace ams::kern {
+ namespace {
+
+ /* Convenience definitions. */
+ constexpr size_t FourGigabytes = 0x100000000ul;
+ constexpr size_t SixGigabytes = 0x180000000ul;
+ constexpr size_t EightGigabytes = 0x200000000ul;
+
+ size_t GetRealMemorySize() {
+ /* TODO: Move this into a header for the MC in general. */
+ constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
+ u32 config_value;
+ MESOSPHERE_ABORT_UNLESS(smc::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
+ return static_cast(config_value & 0x3FFF) << 20;
+ }
+
+ inline u64 GetKernelConfiguration() {
+ u64 value = 0;
+ smc::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration);
+ return value;
+ }
+
+ inline smc::MemoryMode GetMemoryMode() {
+ return static_cast((GetKernelConfiguration() >> 10) & 0x3);
+ }
+
+ size_t GetIntendedMemorySize() {
+ const smc::MemoryMode memory_mode = GetMemoryMode();
+ switch (memory_mode) {
+ case smc::MemoryMode_4GB:
+ default: /* All invalid modes should go to 4GB. */
+ return FourGigabytes;
+ case smc::MemoryMode_6GB:
+ return SixGigabytes;
+ case smc::MemoryMode_8GB:
+ return EightGigabytes;
+ }
+ }
+
+ }
+
+ /* Initialization. */
+ KPhysicalAddress KSystemControl::GetKernelPhysicalBaseAddress(uintptr_t base_address) {
+ const size_t real_dram_size = GetRealMemorySize();
+ const size_t intended_dram_size = GetIntendedMemorySize();
+ if (intended_dram_size * 2 < real_dram_size) {
+ return base_address;
+ } else {
+ return base_address + ((real_dram_size - intended_dram_size) / 2);
+ }
+ }
+
+ bool KSystemControl::ShouldIncreaseResourceRegionSize() {
+ return (GetKernelConfiguration() >> 3) & 1;
+ }
+
void KSystemControl::StopSystem() {
- /* TODO: smc::Panic(0xF00); */
+ /* Display a panic screen via exosphere. */
+ smc::Panic(0xF00);
while (true) { /* ... */ }
}
diff --git a/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp b/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp
new file mode 100644
index 00000000..b56b8371
--- /dev/null
+++ b/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+#include
+#include "kern_secure_monitor.hpp"
+
+namespace ams::kern::smc {
+
+ namespace {
+
+ struct SecureMonitorArguments {
+ u64 x[8];
+ };
+
+ enum FunctionId : u32 {
+ FunctionId_CpuSuspend = 0xC4000001,
+ FunctionId_CpuOff = 0x84000002,
+ FunctionId_CpuOn = 0xC4000003,
+ FunctionId_GetConfig = 0xC3000004,
+ FunctionId_GenerateRandomBytes = 0xC3000005,
+ FunctionId_Panic = 0xC3000006,
+ FunctionId_ConfigureCarveout = 0xC3000007,
+ FunctionId_ReadWriteRegister = 0xC3000008,
+ };
+
+ void CallPrivilegedSecureMonitorFunction(SecureMonitorArguments &args) {
+ /* Load arguments into registers. */
+ register u64 x0 asm("x0") = args.x[0];
+ register u64 x1 asm("x1") = args.x[1];
+ register u64 x2 asm("x2") = args.x[2];
+ register u64 x3 asm("x3") = args.x[3];
+ register u64 x4 asm("x4") = args.x[4];
+ register u64 x5 asm("x5") = args.x[5];
+ register u64 x6 asm("x6") = args.x[6];
+ register u64 x7 asm("x7") = args.x[7];
+
+ /* Actually make the call. */
+ {
+ /* Disable interrupts while making the call. */
+ KScopedInterruptDisable intr_disable;
+ __asm__ __volatile__("smc #1"
+ : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
+ :
+ : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
+ );
+ /* TODO: Restore X18 */
+ }
+
+ /* Store arguments to output. */
+ args.x[0] = x0;
+ args.x[1] = x1;
+ args.x[2] = x2;
+ args.x[3] = x3;
+ args.x[4] = x4;
+ args.x[5] = x5;
+ args.x[6] = x6;
+ args.x[7] = x7;
+ }
+
+ }
+
+ void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
+ SecureMonitorArguments args = { FunctionId_GetConfig, static_cast(config_item) };
+ CallPrivilegedSecureMonitorFunction(args);
+ MESOSPHERE_ABORT_UNLESS((static_cast(args.x[0]) == SmcResult::Success));
+ for (size_t i = 0; i < num_qwords && i < 7; i++) {
+ out[i] = args.x[1 + i];
+ }
+ }
+
+ void NORETURN Panic(u32 color) {
+ SecureMonitorArguments args = { FunctionId_Panic, color };
+ CallPrivilegedSecureMonitorFunction(args);
+ while (true) { /* ... */ }
+ }
+
+ bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) {
+ SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value };
+ CallPrivilegedSecureMonitorFunction(args);
+ *out = args.x[1];
+ return static_cast(args.x[0]) == SmcResult::Success;
+ }
+
+}
\ No newline at end of file
diff --git a/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp b/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp
index 4c5e144f..8100a120 100644
--- a/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp
+++ b/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp
@@ -18,6 +18,54 @@
namespace ams::kern::smc {
- /* TODO: Secure Monitor API. */
+ /* Types. */
+ enum MemoryMode {
+ MemoryMode_4GB = 0,
+ MemoryMode_6GB = 1,
+ MemoryMode_8GB = 2,
+ };
+
+ enum class ConfigItem : u32 {
+ /* Standard config items. */
+ DisableProgramVerification = 1,
+ DramId = 2,
+ SecurityEngineIrqNumber = 3,
+ Version = 4,
+ HardwareType = 5,
+ IsRetail = 6,
+ IsRecoveryBoot = 7,
+ DeviceId = 8,
+ BootReason = 9,
+ MemoryArrange = 10,
+ IsDebugMode = 11,
+ KernelConfiguration = 12,
+ IsChargerHiZModeEnabled = 13,
+ IsKiosk = 14,
+ NewHardwareType = 15,
+ NewKeyGeneration = 16,
+ Package2Hash = 17,
+
+ /* Extension config items for exosphere. */
+ ExosphereApiVersion = 65000,
+ ExosphereNeedsReboot = 65001,
+ ExosphereNeedsShutdown = 65002,
+ ExosphereGitCommitHash = 65003,
+ ExosphereHasRcmBugPatch = 65004,
+ };
+
+ enum class SmcResult {
+ Success = 0,
+ NotImplemented = 1,
+ InvalidArgument = 2,
+ InProgress = 3,
+ NoAsyncOperation = 4,
+ InvalidAsyncOperation = 5,
+ NotPermitted = 6,
+ };
+
+ /* TODO: Rest of Secure Monitor API. */
+ void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
+ void NORETURN Panic(u32 color);
+ bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
}
\ No newline at end of file
diff --git a/libmesosphere/source/kern_k_scoped_interrupt.cpp b/libmesosphere/source/kern_k_scoped_interrupt.cpp
new file mode 100644
index 00000000..1e7c0cce
--- /dev/null
+++ b/libmesosphere/source/kern_k_scoped_interrupt.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-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 .
+ */
+#include
+
+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. */
+ }
+
+}