diff --git a/libraries/config/board/nintendo/nx/board.mk b/libraries/config/board/nintendo/nx/board.mk new file mode 100644 index 0000000..0a7acfc --- /dev/null +++ b/libraries/config/board/nintendo/nx/board.mk @@ -0,0 +1,5 @@ +export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_NX -D__SWITCH__ +export ATMOSPHERE_SETTINGS += +export ATMOSPHERE_CFLAGS += +export ATMOSPHERE_CXXFLAGS += +export ATMOSPHERE_ASFLAGS += \ No newline at end of file diff --git a/libraries/config/board/nintendo/switch/board.mk b/libraries/config/board/nintendo/switch/board.mk deleted file mode 100644 index facdf96..0000000 --- a/libraries/config/board/nintendo/switch/board.mk +++ /dev/null @@ -1,5 +0,0 @@ -export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_SWITCH -D__SWITCH__ -export ATMOSPHERE_SETTINGS += -export ATMOSPHERE_CFLAGS += -export ATMOSPHERE_CXXFLAGS += -export ATMOSPHERE_ASFLAGS += \ No newline at end of file diff --git a/libraries/config/common.mk b/libraries/config/common.mk index e71dc15..7e1c84a 100644 --- a/libraries/config/common.mk +++ b/libraries/config/common.mk @@ -24,11 +24,11 @@ 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 85a4bc3..b09ff06 100644 --- a/libraries/libmesosphere/include/mesosphere.hpp +++ b/libraries/libmesosphere/include/mesosphere.hpp @@ -30,6 +30,7 @@ /* Core pre-initialization includes. */ #include #include +#include /* Initialization headers. */ #include diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp index 1ae915f..3290050 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 @@ #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 5902b11..9790002 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 @@ 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 @@ 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 fdf59b8..0975d65 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 @@ BlockType_L3ContiguousBlock, BlockType_L2Block, -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX BlockType_L2TegraSmmuBlock, #endif @@ -48,14 +48,14 @@ 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 @@ 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 113c477..2b56651 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 @@ 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 + static constexpr ALWAYS_INLINE u64 GetBits(u64 value) { + return (value >> Offset) & ((1ul << Count) - 1); + } + + template + constexpr ALWAYS_INLINE u64 SelectBits(u64 value) { + return value & (((1ul << Count) - 1) << Offset); + } + + static constexpr ALWAYS_INLINE uintptr_t GetL0Index(KProcessAddress addr) { return GetBits(GetInteger(addr)); } + static constexpr ALWAYS_INLINE uintptr_t GetL1Index(KProcessAddress addr) { return GetBits(GetInteger(addr)); } + static constexpr ALWAYS_INLINE uintptr_t GetL2Index(KProcessAddress addr) { return GetBits(GetInteger(addr)); } + static constexpr ALWAYS_INLINE uintptr_t GetL3Index(KProcessAddress addr) { return GetBits(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(GetTableEntry(KVirtualAddress(this->table), (GetInteger(address) >> (PageBits + LevelBits * 2)) & (this->num_entries - 1))); + ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) const { + return GetPointer(GetTableEntry(KVirtualAddress(this->table), GetL1Index(address) & (this->num_entries - 1))); } - ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) { - return GetPointer(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 1)) & ((1ul << LevelBits) - 1))); + ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) const { + return GetPointer(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(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 0)) & ((1ul << LevelBits) - 1))); + ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) const { + return GetPointer(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 c330696..6596e70 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 @@ 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/nx/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp new file mode 100644 index 0000000..e14c734 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp @@ -0,0 +1,53 @@ +/* + * 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::board::nintendo::nx { + + class KSystemControl { + public: + class Init { + public: + /* Initialization. */ + static size_t GetIntendedMemorySize(); + static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address); + static bool ShouldIncreaseThreadResourceLimit(); + static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg); + static size_t GetApplicationPoolSize(); + static size_t GetAppletPoolSize(); + static size_t GetMinimumNonSecureSystemPoolSize(); + + /* Randomness. */ + static void GenerateRandomBytes(void *dst, size_t size); + static u64 GenerateRandomRange(u64 min, u64 max); + }; + public: + /* Initialization. */ + 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); + + /* Power management. */ + static void SleepSystem(); + static NORETURN void StopSystem(); + }; + +} \ No newline at end of file diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp deleted file mode 100644 index 3572d08..0000000 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 KSystemControl { - public: - class Init { - public: - /* Initialization. */ - static size_t GetIntendedMemorySize(); - static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address); - static bool ShouldIncreaseThreadResourceLimit(); - static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg); - static size_t GetApplicationPoolSize(); - static size_t GetAppletPoolSize(); - static size_t GetMinimumNonSecureSystemPoolSize(); - - /* Randomness. */ - static void GenerateRandomBytes(void *dst, size_t size); - static u64 GenerateRandomRange(u64 min, u64 max); - }; - public: - /* Initialization. */ - static NOINLINE void Initialize(); - static NOINLINE u32 GetInitialProcessBinaryPool(); - - /* Randomness. */ - static void GenerateRandomBytes(void *dst, size_t size); - static u64 GenerateRandomRange(u64 min, u64 max); - - /* Panic. */ - static NORETURN void StopSystem(); - }; - -} \ No newline at end of file diff --git a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp index bb4d4e9..85a7079 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp @@ -32,7 +32,7 @@ #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 aceefcd..e07ce69 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 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 f2a3c30..68f5ab3 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 @@ 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 123595b..2134f83 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 +#include 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 a675d51..25df4ae 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 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 75c0a40..5d4890d 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 -#include -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH - #include +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX + #include + + 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 a97266d..368c029 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 @@ void KPageTableImpl::InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end) { this->table = static_cast(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 0000000..3846b17 --- /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 . + */ +#include +#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(g_sleep_buffers[core_id]), SleepManagerThreadPriority, static_cast(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; + + /* 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 0000000..1cc500c --- /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 . + */ +#pragma once +#include + +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 0000000..1c4a014 --- /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 . + */ + +/* 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/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp new file mode 100644 index 0000000..c0c6cd8 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -0,0 +1,311 @@ +/* + * 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 +#include "kern_secure_monitor.hpp" +#include "kern_k_sleep_manager.hpp" + +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), */ + /* We will use TinyMT. */ + bool g_initialized_random_generator; + util::TinyMT g_random_generator; + KSpinLock g_random_lock; + + ALWAYS_INLINE size_t GetRealMemorySizeForInit() { + /* TODO: Move this into a header for the MC in general. */ + constexpr u32 MemoryControllerConfigurationRegister = 0x70019050; + u32 config_value; + MESOSPHERE_INIT_ABORT_UNLESS(smc::init::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0)); + return static_cast(config_value & 0x3FFF) << 20; + } + + ALWAYS_INLINE util::BitPack32 GetKernelConfigurationForInit() { + u64 value = 0; + smc::init::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration); + return util::BitPack32{static_cast(value)}; + } + + ALWAYS_INLINE u32 GetMemoryModeForInit() { + u64 value = 0; + smc::init::GetConfig(&value, 1, smc::ConfigItem::MemoryMode); + return static_cast(value); + } + + ALWAYS_INLINE smc::MemoryArrangement GetMemoryArrangeForInit() { + switch(GetMemoryModeForInit() & 0x3F) { + case 0x01: + default: + return smc::MemoryArrangement_4GB; + case 0x02: + return smc::MemoryArrangement_4GBForAppletDev; + case 0x03: + return smc::MemoryArrangement_4GBForSystemDev; + case 0x11: + return smc::MemoryArrangement_6GB; + case 0x12: + return smc::MemoryArrangement_6GBForAppletDev; + case 0x21: + return smc::MemoryArrangement_8GB; + } + } + + ALWAYS_INLINE u64 GenerateRandomU64ForInit() { + u64 value; + smc::init::GenerateRandomBytes(&value, sizeof(value)); + return value; + } + + ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() { + return g_random_generator.GenerateRandomU64(); + } + + template + ALWAYS_INLINE u64 GenerateUniformRange(u64 min, u64 max, F f) { + /* Handle the case where the difference is too large to represent. */ + if (max == std::numeric_limits::max() && min == std::numeric_limits::min()) { + return f(); + } + + /* Iterate until we get a value in range. */ + const u64 range_size = ((max + 1) - min); + const u64 effective_max = (std::numeric_limits::max() / range_size) * range_size; + while (true) { + if (const u64 rnd = f(); rnd < effective_max) { + return min + (rnd % range_size); + } + } + } + + ALWAYS_INLINE u64 GetConfigU64(smc::ConfigItem which) { + u64 value; + smc::GetConfig(&value, 1, which); + return value; + } + + ALWAYS_INLINE u32 GetConfigU32(smc::ConfigItem which) { + return static_cast(GetConfigU64(which)); + } + + ALWAYS_INLINE bool GetConfigBool(smc::ConfigItem which) { + return GetConfigU64(which) != 0; + } + + } + + /* Initialization. */ + size_t KSystemControl::Init::GetIntendedMemorySize() { + switch (GetKernelConfigurationForInit().Get()) { + case smc::MemorySize_4GB: + default: /* All invalid modes should go to 4GB. */ + return 4_GB; + case smc::MemorySize_6GB: + return 6_GB; + case smc::MemorySize_8GB: + return 8_GB; + } + } + + KPhysicalAddress KSystemControl::Init::GetKernelPhysicalBaseAddress(uintptr_t base_address) { + const size_t real_dram_size = GetRealMemorySizeForInit(); + const size_t intended_dram_size = KSystemControl::Init::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::Init::ShouldIncreaseThreadResourceLimit() { + return GetKernelConfigurationForInit().Get(); + } + + size_t KSystemControl::Init::GetApplicationPoolSize() { + switch (GetMemoryArrangeForInit()) { + case smc::MemoryArrangement_4GB: + default: + return 3285_MB; + case smc::MemoryArrangement_4GBForAppletDev: + return 2048_MB; + case smc::MemoryArrangement_4GBForSystemDev: + return 3285_MB; + case smc::MemoryArrangement_6GB: + return 4916_MB; + case smc::MemoryArrangement_6GBForAppletDev: + return 3285_MB; + case smc::MemoryArrangement_8GB: + return 4916_MB; + } + } + + size_t KSystemControl::Init::GetAppletPoolSize() { + switch (GetMemoryArrangeForInit()) { + case smc::MemoryArrangement_4GB: + default: + return 507_MB; + case smc::MemoryArrangement_4GBForAppletDev: + return 1554_MB; + case smc::MemoryArrangement_4GBForSystemDev: + return 448_MB; + case smc::MemoryArrangement_6GB: + return 562_MB; + case smc::MemoryArrangement_6GBForAppletDev: + return 2193_MB; + case smc::MemoryArrangement_8GB: + return 2193_MB; + } + } + + size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() { + /* TODO: Where does this constant actually come from? */ + return 0x29C8000; + } + + void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { + smc::init::CpuOn(core_id, entrypoint, arg); + } + + /* Randomness for Initialization. */ + void KSystemControl::Init::GenerateRandomBytes(void *dst, size_t size) { + MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38); + smc::init::GenerateRandomBytes(dst, size); + } + + u64 KSystemControl::Init::GenerateRandomRange(u64 min, u64 max) { + return GenerateUniformRange(min, max, GenerateRandomU64ForInit); + } + + /* System Initialization. */ + void KSystemControl::InitializePhase1() { + /* Set IsDebugMode. */ + { + KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); + + /* If debug mode, we want to initialize uart logging. */ + KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode()); + KDebugLog::Initialize(); + } + + /* Set Kernel Configuration. */ + { + const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; + + KTargetSystem::EnableDebugMemoryFill(kernel_config.Get()); + KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get()); + KTargetSystem::EnableUserPmuAccess(kernel_config.Get()); + + g_call_smc_on_panic = kernel_config.Get(); + } + + /* Set Kernel Debugging. */ + { + /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */ + /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */ + KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification)); + } + + /* Configure the Kernel Carveout region. */ + { + const auto carveout = KMemoryLayout::GetCarveoutRegionExtents(); + smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize()); + } + + /* System ResourceLimit initialization. */ + { + /* Construct the resource limit object. */ + KResourceLimit &sys_res_limit = Kernel::GetSystemResourceLimit(); + KAutoObject::Create(std::addressof(sys_res_limit)); + sys_res_limit.Initialize(); + + /* Set the initial limits. */ + const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes(); + const auto &slab_counts = init::GetSlabResourceCounts(); + MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size)); + MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread)); + MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_EventCountMax, slab_counts.num_KEvent)); + MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_TransferMemoryCountMax, slab_counts.num_KTransferMemory)); + MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_SessionCountMax, slab_counts.num_KSession)); + + /* Reserve system memory. */ + MESOSPHERE_ABORT_UNLESS(sys_res_limit.Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, kernel_memory_size)); + } + } + + void KSystemControl::InitializePhase2() { + /* Initialize the sleep manager. */ + KSleepManager::Initialize(); + + /* Reserve secure applet memory. */ + { + MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null); + 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); + } + } + + u32 KSystemControl::GetInitialProcessBinaryPool() { + return KMemoryManager::Pool_Application; + } + + /* Randomness. */ + void KSystemControl::GenerateRandomBytes(void *dst, size_t size) { + MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38); + smc::GenerateRandomBytes(dst, size); + } + + u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) { + KScopedInterruptDisable intr_disable; + KScopedSpinLock lk(g_random_lock); + + if (AMS_UNLIKELY(!g_initialized_random_generator)) { + u64 seed; + GenerateRandomBytes(&seed, sizeof(seed)); + g_random_generator.Initialize(reinterpret_cast(&seed), sizeof(seed) / sizeof(u32)); + g_initialized_random_generator = true; + } + + 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. */ + /* TODO: Enable in release: smc::Panic(0xF00); */ + } + while (true) { /* ... */ } + } + +} \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp new file mode 100644 index 0000000..d3797d7 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp @@ -0,0 +1,184 @@ +/* + * 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 +#include "kern_secure_monitor.hpp" + +namespace ams::kern::board::nintendo::nx::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" + ); + + /* Restore the CoreLocalRegion into X18. */ + cpu::SetCoreLocalRegionAddress(cpu::GetTpidrEl1()); + } + + /* 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 CallPrivilegedSecureMonitorFunctionForInit(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. */ + __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" + ); + + /* 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; + } + + /* Global lock for generate random bytes. */ + KSpinLock g_generate_random_lock; + + } + + /* SMC functionality needed for init. */ + namespace init { + + void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { + SecureMonitorArguments args = { FunctionId_CpuOn, core_id, entrypoint, arg }; + CallPrivilegedSecureMonitorFunctionForInit(args); + } + + void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { + SecureMonitorArguments args = { FunctionId_GetConfig, static_cast(config_item) }; + CallPrivilegedSecureMonitorFunctionForInit(args); + MESOSPHERE_INIT_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 GenerateRandomBytes(void *dst, size_t size) { + /* Call SmcGenerateRandomBytes() */ + SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size }; + MESOSPHERE_INIT_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0])); + + CallPrivilegedSecureMonitorFunctionForInit(args); + MESOSPHERE_INIT_ABORT_UNLESS((static_cast(args.x[0]) == SmcResult::Success)); + + /* Copy output. */ + std::memcpy(dst, &args.x[1], size); + } + + bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) { + SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value }; + CallPrivilegedSecureMonitorFunctionForInit(args); + *out = args.x[1]; + return static_cast(args.x[0]) == SmcResult::Success; + } + + } + + 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 ConfigureCarveout(size_t which, uintptr_t address, size_t size) { + SecureMonitorArguments args = { FunctionId_ConfigureCarveout, static_cast(which), static_cast(address), static_cast(size) }; + CallPrivilegedSecureMonitorFunction(args); + MESOSPHERE_ABORT_UNLESS((static_cast(args.x[0]) == SmcResult::Success)); + } + + void GenerateRandomBytes(void *dst, size_t size) { + /* Setup for call. */ + SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size }; + MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0])); + + /* Make call. */ + { + KScopedInterruptDisable intr_disable; + KScopedSpinLock lk(g_generate_random_lock); + CallPrivilegedSecureMonitorFunction(args); + } + MESOSPHERE_ABORT_UNLESS((static_cast(args.x[0]) == SmcResult::Success)); + + /* Copy output. */ + std::memcpy(dst, &args.x[1], size); + } + + void NORETURN Panic(u32 color) { + SecureMonitorArguments args = { FunctionId_Panic, color }; + CallPrivilegedSecureMonitorFunction(args); + while (true) { /* ... */ } + } + +} \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp new file mode 100644 index 0000000..dcf1c4d --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp @@ -0,0 +1,101 @@ +/* + * 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::board::nintendo::nx::smc { + + /* Types. */ + enum MemorySize { + MemorySize_4GB = 0, + MemorySize_6GB = 1, + MemorySize_8GB = 2, + }; + + enum MemoryArrangement { + MemoryArrangement_4GB = 0, + MemoryArrangement_4GBForAppletDev = 1, + MemoryArrangement_4GBForSystemDev = 2, + MemoryArrangement_6GB = 3, + MemoryArrangement_6GBForAppletDev = 4, + MemoryArrangement_8GB = 5, + }; + + 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, + MemoryMode = 10, + IsDebugMode = 11, + KernelConfiguration = 12, + IsChargerHiZModeEnabled = 13, + IsQuest = 14, + RegulatorType = 15, + DeviceUniqueKeyGeneration = 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, + }; + + struct KernelConfiguration { + using DebugFillMemory = util::BitPack32::Field<0, 1, bool>; + using EnableUserExceptionHandlers = util::BitPack32::Field; + using EnableUserPmuAccess = util::BitPack32::Field; + using IncreaseThreadResourceLimit = util::BitPack32::Field; + using Reserved4 = util::BitPack32::Field; + using UseSecureMonitorPanicCall = util::BitPack32::Field; + using Reserved9 = util::BitPack32::Field; + using MemorySize = util::BitPack32::Field; + }; + + /* TODO: Rest of Secure Monitor API. */ + void GenerateRandomBytes(void *dst, size_t size); + void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); + void ConfigureCarveout(size_t which, uintptr_t address, size_t size); + void NORETURN Panic(u32 color); + + namespace init { + + void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg); + void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); + void GenerateRandomBytes(void *dst, size_t size); + bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value); + + } + +} \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp b/libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp deleted file mode 100644 index 8985447..0000000 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 -#include "../../../kern_debug_log_impl.hpp" - -namespace ams::kern { - - namespace { - - enum UartRegister { - UartRegister_THR = 0, - UartRegister_IER = 1, - UartRegister_FCR = 2, - UartRegister_LCR = 3, - - UartRegister_LSR = 5, - - UartRegister_IRSA_CSR = 8, - - UartRegister_DLL = 0, - UartRegister_DLH = 1, - }; - - KVirtualAddress g_uart_address = 0; - - NOINLINE u32 ReadUartRegister(UartRegister which) { - return GetPointer(g_uart_address)[which]; - } - - NOINLINE void WriteUartRegister(UartRegister which, u32 value) { - GetPointer(g_uart_address)[which] = value; - } - - } - - bool KDebugLogImpl::Initialize() { - /* Set the uart register base address. */ - g_uart_address = KMemoryLayout::GetUartAddress(); - - /* Parameters for uart. */ - constexpr u32 BaudRate = 115200; - constexpr u32 Pllp = 408000000; - constexpr u32 Rate = 16 * BaudRate; - constexpr u32 Divisor = (Pllp + Rate / 2) / Rate; - - /* Initialize the UART registers. */ - /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ - WriteUartRegister(UartRegister_LCR, 0x80); - ReadUartRegister(UartRegister_LCR); - - /* Program the divisor into DLL/DLH. */ - WriteUartRegister(UartRegister_DLL, Divisor & 0xFF); - WriteUartRegister(UartRegister_DLH, (Divisor >> 8) & 0xFF); - ReadUartRegister(UartRegister_DLH); - - /* Set word length to 3, clear Divisor Latch Access. */ - WriteUartRegister(UartRegister_LCR, 0x03); - ReadUartRegister(UartRegister_LCR); - - /* Disable UART interrupts. */ - WriteUartRegister(UartRegister_IER, 0x00); - - /* Configure the FIFO to be enabled and clear receive. */ - WriteUartRegister(UartRegister_FCR, 0x03); - WriteUartRegister(UartRegister_IRSA_CSR, 0x02); - ReadUartRegister(UartRegister_FCR); - - return true; - } - - void KDebugLogImpl::PutChar(char c) { - while (ReadUartRegister(UartRegister_LSR) & 0x100) { - /* While the FIFO is full, yield. */ - __asm__ __volatile__("yield" ::: "memory"); - } - WriteUartRegister(UartRegister_THR, c); - cpu::DataSynchronizationBarrier(); - } - - void KDebugLogImpl::Flush() { - while ((ReadUartRegister(UartRegister_LSR) & 0x40) == 0) { - /* Wait for the TMTY bit to be one (transmit empty). */ - } - } - -} diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_memory_layout.board.nintendo_switch.cpp b/libraries/libmesosphere/source/board/nintendo/switch/kern_k_memory_layout.board.nintendo_switch.cpp deleted file mode 100644 index d36c45c..0000000 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_memory_layout.board.nintendo_switch.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 { - - namespace { - - constexpr uintptr_t DramPhysicalAddress = 0x80000000; - constexpr size_t ReservedEarlyDramSize = 0x60000; - - ALWAYS_INLINE bool SetupUartPhysicalMemoryRegion() { - #if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006000, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006040, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #else - #error "Unknown Debug UART device!" - #endif - } - - } - - namespace init { - - void SetupDevicePhysicalMemoryRegions() { - /* TODO: Give these constexpr defines somewhere? */ - MESOSPHERE_INIT_ABORT_UNLESS(SetupUartPhysicalMemoryRegion()); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E000, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E400, 0xC00, KMemoryRegionType_PowerManagementController | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50041000, 0x1000, KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50042000, 0x1000, KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - } - - void SetupDramPhysicalMemoryRegions() { - const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize(); - const KPhysicalAddress physical_memory_base_address = KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress); - - /* Insert blocks into the tree. */ - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly)); - } - - } - -} \ 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/switch/kern_k_system_control.cpp deleted file mode 100644 index 4e65315..0000000 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* - * 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 -#include "kern_secure_monitor.hpp" - -namespace ams::kern { - - namespace { - - /* Global variables for panic. */ - bool g_call_smc_on_panic; - - /* Global variables for randomness. */ - /* Nintendo uses std::mt19937_t for randomness. */ - /* To save space (and because mt19337_t isn't secure anyway), */ - /* We will use TinyMT. */ - bool g_initialized_random_generator; - util::TinyMT g_random_generator; - KSpinLock g_random_lock; - - ALWAYS_INLINE size_t GetRealMemorySizeForInit() { - /* TODO: Move this into a header for the MC in general. */ - constexpr u32 MemoryControllerConfigurationRegister = 0x70019050; - u32 config_value; - MESOSPHERE_INIT_ABORT_UNLESS(smc::init::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0)); - return static_cast(config_value & 0x3FFF) << 20; - } - - ALWAYS_INLINE util::BitPack32 GetKernelConfigurationForInit() { - u64 value = 0; - smc::init::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration); - return util::BitPack32{static_cast(value)}; - } - - ALWAYS_INLINE u32 GetMemoryModeForInit() { - u64 value = 0; - smc::init::GetConfig(&value, 1, smc::ConfigItem::MemoryMode); - return static_cast(value); - } - - ALWAYS_INLINE smc::MemoryArrangement GetMemoryArrangeForInit() { - switch(GetMemoryModeForInit() & 0x3F) { - case 0x01: - default: - return smc::MemoryArrangement_4GB; - case 0x02: - return smc::MemoryArrangement_4GBForAppletDev; - case 0x03: - return smc::MemoryArrangement_4GBForSystemDev; - case 0x11: - return smc::MemoryArrangement_6GB; - case 0x12: - return smc::MemoryArrangement_6GBForAppletDev; - case 0x21: - return smc::MemoryArrangement_8GB; - } - } - - ALWAYS_INLINE u64 GenerateRandomU64ForInit() { - u64 value; - smc::init::GenerateRandomBytes(&value, sizeof(value)); - return value; - } - - ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() { - return g_random_generator.GenerateRandomU64(); - } - - template - ALWAYS_INLINE u64 GenerateUniformRange(u64 min, u64 max, F f) { - /* Handle the case where the difference is too large to represent. */ - if (max == std::numeric_limits::max() && min == std::numeric_limits::min()) { - return f(); - } - - /* Iterate until we get a value in range. */ - const u64 range_size = ((max + 1) - min); - const u64 effective_max = (std::numeric_limits::max() / range_size) * range_size; - while (true) { - if (const u64 rnd = f(); rnd < effective_max) { - return min + (rnd % range_size); - } - } - } - - ALWAYS_INLINE u64 GetConfigU64(smc::ConfigItem which) { - u64 value; - smc::GetConfig(&value, 1, which); - return value; - } - - ALWAYS_INLINE u32 GetConfigU32(smc::ConfigItem which) { - return static_cast(GetConfigU64(which)); - } - - ALWAYS_INLINE bool GetConfigBool(smc::ConfigItem which) { - return GetConfigU64(which) != 0; - } - - } - - /* Initialization. */ - size_t KSystemControl::Init::GetIntendedMemorySize() { - switch (GetKernelConfigurationForInit().Get()) { - case smc::MemorySize_4GB: - default: /* All invalid modes should go to 4GB. */ - return 4_GB; - case smc::MemorySize_6GB: - return 6_GB; - case smc::MemorySize_8GB: - return 8_GB; - } - } - - KPhysicalAddress KSystemControl::Init::GetKernelPhysicalBaseAddress(uintptr_t base_address) { - const size_t real_dram_size = GetRealMemorySizeForInit(); - const size_t intended_dram_size = KSystemControl::Init::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::Init::ShouldIncreaseThreadResourceLimit() { - return GetKernelConfigurationForInit().Get(); - } - - size_t KSystemControl::Init::GetApplicationPoolSize() { - switch (GetMemoryArrangeForInit()) { - case smc::MemoryArrangement_4GB: - default: - return 3285_MB; - case smc::MemoryArrangement_4GBForAppletDev: - return 2048_MB; - case smc::MemoryArrangement_4GBForSystemDev: - return 3285_MB; - case smc::MemoryArrangement_6GB: - return 4916_MB; - case smc::MemoryArrangement_6GBForAppletDev: - return 3285_MB; - case smc::MemoryArrangement_8GB: - return 4916_MB; - } - } - - size_t KSystemControl::Init::GetAppletPoolSize() { - switch (GetMemoryArrangeForInit()) { - case smc::MemoryArrangement_4GB: - default: - return 507_MB; - case smc::MemoryArrangement_4GBForAppletDev: - return 1554_MB; - case smc::MemoryArrangement_4GBForSystemDev: - return 448_MB; - case smc::MemoryArrangement_6GB: - return 562_MB; - case smc::MemoryArrangement_6GBForAppletDev: - return 2193_MB; - case smc::MemoryArrangement_8GB: - return 2193_MB; - } - } - - size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() { - /* TODO: Where does this constant actually come from? */ - return 0x29C8000; - } - - void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { - smc::init::CpuOn(core_id, entrypoint, arg); - } - - /* Randomness for Initialization. */ - void KSystemControl::Init::GenerateRandomBytes(void *dst, size_t size) { - MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38); - smc::init::GenerateRandomBytes(dst, size); - } - - u64 KSystemControl::Init::GenerateRandomRange(u64 min, u64 max) { - return GenerateUniformRange(min, max, GenerateRandomU64ForInit); - } - - /* System Initialization. */ - void KSystemControl::Initialize() { - /* Set IsDebugMode. */ - { - KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); - - /* If debug mode, we want to initialize uart logging. */ - KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode()); - KDebugLog::Initialize(); - } - - /* Set Kernel Configuration. */ - { - const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; - - KTargetSystem::EnableDebugMemoryFill(kernel_config.Get()); - KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get()); - KTargetSystem::EnableUserPmuAccess(kernel_config.Get()); - - g_call_smc_on_panic = kernel_config.Get(); - } - - /* Set Kernel Debugging. */ - { - /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */ - /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */ - KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification)); - } - - /* Configure the Kernel Carveout region. */ - { - const auto carveout = KMemoryLayout::GetCarveoutRegionExtents(); - smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize()); - } - - /* System ResourceLimit initialization. */ - { - /* Construct the resource limit object. */ - KResourceLimit &sys_res_limit = Kernel::GetSystemResourceLimit(); - KAutoObject::Create(std::addressof(sys_res_limit)); - sys_res_limit.Initialize(); - - /* Set the initial limits. */ - const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes(); - const auto &slab_counts = init::GetSlabResourceCounts(); - MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size)); - MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread)); - MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_EventCountMax, slab_counts.num_KEvent)); - MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_TransferMemoryCountMax, slab_counts.num_KTransferMemory)); - MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_SessionCountMax, slab_counts.num_KSession)); - - /* Reserve system memory. */ - MESOSPHERE_ABORT_UNLESS(sys_res_limit.Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, kernel_memory_size)); - } - } - - u32 KSystemControl::GetInitialProcessBinaryPool() { - return KMemoryManager::Pool_Application; - } - - /* Randomness. */ - void KSystemControl::GenerateRandomBytes(void *dst, size_t size) { - MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38); - smc::GenerateRandomBytes(dst, size); - } - - u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) { - KScopedInterruptDisable intr_disable; - KScopedSpinLock lk(g_random_lock); - - if (AMS_UNLIKELY(!g_initialized_random_generator)) { - u64 seed; - GenerateRandomBytes(&seed, sizeof(seed)); - g_random_generator.Initialize(reinterpret_cast(&seed), sizeof(seed) / sizeof(u32)); - g_initialized_random_generator = true; - } - - return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator); - } - - void KSystemControl::StopSystem() { - if (g_call_smc_on_panic) { - /* Display a panic screen via secure monitor. */ - /* TODO: Enable in release: smc::Panic(0xF00); */ - } - while (true) { /* ... */ } - } - -} \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp b/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp deleted file mode 100644 index 7c49443..0000000 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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 -#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" - ); - - /* Restore the CoreLocalRegion into X18. */ - cpu::SetCoreLocalRegionAddress(cpu::GetTpidrEl1()); - } - - /* 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 CallPrivilegedSecureMonitorFunctionForInit(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. */ - __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" - ); - - /* 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; - } - - /* Global lock for generate random bytes. */ - KSpinLock g_generate_random_lock; - - } - - /* SMC functionality needed for init. */ - namespace init { - - void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { - SecureMonitorArguments args = { FunctionId_CpuOn, core_id, entrypoint, arg }; - CallPrivilegedSecureMonitorFunctionForInit(args); - } - - void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { - SecureMonitorArguments args = { FunctionId_GetConfig, static_cast(config_item) }; - CallPrivilegedSecureMonitorFunctionForInit(args); - MESOSPHERE_INIT_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 GenerateRandomBytes(void *dst, size_t size) { - /* Call SmcGenerateRandomBytes() */ - SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size }; - MESOSPHERE_INIT_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0])); - - CallPrivilegedSecureMonitorFunctionForInit(args); - MESOSPHERE_INIT_ABORT_UNLESS((static_cast(args.x[0]) == SmcResult::Success)); - - /* Copy output. */ - std::memcpy(dst, &args.x[1], size); - } - - bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) { - SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value }; - CallPrivilegedSecureMonitorFunctionForInit(args); - *out = args.x[1]; - return static_cast(args.x[0]) == SmcResult::Success; - } - - } - - 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 ConfigureCarveout(size_t which, uintptr_t address, size_t size) { - SecureMonitorArguments args = { FunctionId_ConfigureCarveout, static_cast(which), static_cast(address), static_cast(size) }; - CallPrivilegedSecureMonitorFunction(args); - MESOSPHERE_ABORT_UNLESS((static_cast(args.x[0]) == SmcResult::Success)); - } - - void GenerateRandomBytes(void *dst, size_t size) { - /* Setup for call. */ - SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size }; - MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0])); - - /* Make call. */ - { - KScopedInterruptDisable intr_disable; - KScopedSpinLock lk(g_generate_random_lock); - CallPrivilegedSecureMonitorFunction(args); - } - MESOSPHERE_ABORT_UNLESS((static_cast(args.x[0]) == SmcResult::Success)); - - /* Copy output. */ - std::memcpy(dst, &args.x[1], size); - } - - void NORETURN Panic(u32 color) { - SecureMonitorArguments args = { FunctionId_Panic, color }; - CallPrivilegedSecureMonitorFunction(args); - while (true) { /* ... */ } - } - -} \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp b/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp deleted file mode 100644 index 14c1fc3..0000000 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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::smc { - - /* Types. */ - enum MemorySize { - MemorySize_4GB = 0, - MemorySize_6GB = 1, - MemorySize_8GB = 2, - }; - - enum MemoryArrangement { - MemoryArrangement_4GB = 0, - MemoryArrangement_4GBForAppletDev = 1, - MemoryArrangement_4GBForSystemDev = 2, - MemoryArrangement_6GB = 3, - MemoryArrangement_6GBForAppletDev = 4, - MemoryArrangement_8GB = 5, - }; - - 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, - MemoryMode = 10, - IsDebugMode = 11, - KernelConfiguration = 12, - IsChargerHiZModeEnabled = 13, - IsQuest = 14, - RegulatorType = 15, - DeviceUniqueKeyGeneration = 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, - }; - - struct KernelConfiguration { - using DebugFillMemory = util::BitPack32::Field<0, 1, bool>; - using EnableUserExceptionHandlers = util::BitPack32::Field; - using EnableUserPmuAccess = util::BitPack32::Field; - using IncreaseThreadResourceLimit = util::BitPack32::Field; - using Reserved4 = util::BitPack32::Field; - using UseSecureMonitorPanicCall = util::BitPack32::Field; - using Reserved9 = util::BitPack32::Field; - using MemorySize = util::BitPack32::Field; - }; - - /* TODO: Rest of Secure Monitor API. */ - void GenerateRandomBytes(void *dst, size_t size); - void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); - void ConfigureCarveout(size_t which, uintptr_t address, size_t size); - void NORETURN Panic(u32 color); - - namespace init { - - void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg); - void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); - void GenerateRandomBytes(void *dst, size_t size); - bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value); - - } - -} \ No newline at end of file diff --git a/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp new file mode 100644 index 0000000..e90cbc7 --- /dev/null +++ b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp @@ -0,0 +1,99 @@ +/* + * 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 +#include "kern_debug_log_impl.hpp" + +namespace ams::kern { + + namespace { + + enum UartRegister { + UartRegister_THR = 0, + UartRegister_IER = 1, + UartRegister_FCR = 2, + UartRegister_LCR = 3, + + UartRegister_LSR = 5, + + UartRegister_IRSA_CSR = 8, + + UartRegister_DLL = 0, + UartRegister_DLH = 1, + }; + + KVirtualAddress g_uart_address = 0; + + NOINLINE u32 ReadUartRegister(UartRegister which) { + return GetPointer(g_uart_address)[which]; + } + + NOINLINE void WriteUartRegister(UartRegister which, u32 value) { + GetPointer(g_uart_address)[which] = value; + } + + } + + bool KDebugLogImpl::Initialize() { + /* Set the uart register base address. */ + g_uart_address = KMemoryLayout::GetUartAddress(); + + /* Parameters for uart. */ + constexpr u32 BaudRate = 115200; + constexpr u32 Pllp = 408000000; + constexpr u32 Rate = 16 * BaudRate; + constexpr u32 Divisor = (Pllp + Rate / 2) / Rate; + + /* Initialize the UART registers. */ + /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ + WriteUartRegister(UartRegister_LCR, 0x80); + ReadUartRegister(UartRegister_LCR); + + /* Program the divisor into DLL/DLH. */ + WriteUartRegister(UartRegister_DLL, Divisor & 0xFF); + WriteUartRegister(UartRegister_DLH, (Divisor >> 8) & 0xFF); + ReadUartRegister(UartRegister_DLH); + + /* Set word length to 3, clear Divisor Latch Access. */ + WriteUartRegister(UartRegister_LCR, 0x03); + ReadUartRegister(UartRegister_LCR); + + /* Disable UART interrupts. */ + WriteUartRegister(UartRegister_IER, 0x00); + + /* Configure the FIFO to be enabled and clear receive. */ + WriteUartRegister(UartRegister_FCR, 0x03); + WriteUartRegister(UartRegister_IRSA_CSR, 0x02); + ReadUartRegister(UartRegister_FCR); + + return true; + } + + void KDebugLogImpl::PutChar(char c) { + while (ReadUartRegister(UartRegister_LSR) & 0x100) { + /* While the FIFO is full, yield. */ + __asm__ __volatile__("yield" ::: "memory"); + } + WriteUartRegister(UartRegister_THR, c); + cpu::DataSynchronizationBarrier(); + } + + void KDebugLogImpl::Flush() { + while ((ReadUartRegister(UartRegister_LSR) & 0x40) == 0) { + /* Wait for the TMTY bit to be one (transmit empty). */ + } + } + +} diff --git a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp new file mode 100644 index 0000000..d36c45c --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp @@ -0,0 +1,70 @@ +/* + * 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 { + + namespace { + + constexpr uintptr_t DramPhysicalAddress = 0x80000000; + constexpr size_t ReservedEarlyDramSize = 0x60000; + + ALWAYS_INLINE bool SetupUartPhysicalMemoryRegion() { + #if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) + return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006000, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) + return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006040, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) + return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D) + return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + #else + #error "Unknown Debug UART device!" + #endif + } + + } + + namespace init { + + void SetupDevicePhysicalMemoryRegions() { + /* TODO: Give these constexpr defines somewhere? */ + MESOSPHERE_INIT_ABORT_UNLESS(SetupUartPhysicalMemoryRegion()); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E000, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E400, 0xC00, KMemoryRegionType_PowerManagementController | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50041000, 0x1000, KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50042000, 0x1000, KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + } + + void SetupDramPhysicalMemoryRegions() { + const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize(); + const KPhysicalAddress physical_memory_base_address = KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress); + + /* Insert blocks into the tree. */ + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly)); + } + + } + +} \ No newline at end of file diff --git a/libraries/libmesosphere/source/kern_main.cpp b/libraries/libmesosphere/source/kern_main.cpp index bafa88c..9d06110 100644 --- a/libraries/libmesosphere/source/kern_main.cpp +++ b/libraries/libmesosphere/source/kern_main.cpp @@ -46,8 +46,8 @@ }); 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 @@ /* 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 7e1bc68..64ac45e 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/nx/svc_device_name.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp new file mode 100644 index 0000000..fb289dd --- /dev/null +++ b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp @@ -0,0 +1,65 @@ +/* + * 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::svc::board::nintendo::nx { + + enum DeviceName { + DeviceName_Afi = 0, + DeviceName_Avpc = 1, + DeviceName_Dc = 2, + DeviceName_Dcb = 3, + DeviceName_Hc = 4, + DeviceName_Hda = 5, + DeviceName_Isp2 = 6, + DeviceName_MsencNvenc = 7, + DeviceName_Nv = 8, + DeviceName_Nv2 = 9, + DeviceName_Ppcs = 10, + DeviceName_Sata = 11, + DeviceName_Vi = 12, + DeviceName_Vic = 13, + DeviceName_XusbHost = 14, + DeviceName_XusbDev = 15, + DeviceName_Tsec = 16, + DeviceName_Ppcs1 = 17, + DeviceName_Dc1 = 18, + DeviceName_Sdmmc1a = 19, + DeviceName_Sdmmc2a = 20, + DeviceName_Sdmmc3a = 21, + DeviceName_Sdmmc4a = 22, + DeviceName_Isp2b = 23, + DeviceName_Gpu = 24, + DeviceName_Gpub = 25, + DeviceName_Ppcs2 = 26, + DeviceName_Nvdec = 27, + DeviceName_Ape = 28, + DeviceName_Se = 29, + DeviceName_Nvjpg = 30, + DeviceName_Hc1 = 31, + DeviceName_Se1 = 32, + DeviceName_Axiap = 33, + DeviceName_Etr = 34, + DeviceName_Tsecb = 35, + DeviceName_Tsec1 = 36, + DeviceName_Tsecb1 = 37, + DeviceName_Nvdec1 = 38, + + DeviceName_Count, + }; + +} diff --git a/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp new file mode 100644 index 0000000..8b270b1 --- /dev/null +++ b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp @@ -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 . + */ +#pragma once +#include + +namespace ams::svc::board::nintendo::nx { + + constexpr inline const s64 TicksPerSecond = 19'200'000; + +} diff --git a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp deleted file mode 100644 index f1175d7..0000000 --- a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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::svc::board::nintendo_switch { - - enum DeviceName { - DeviceName_Afi = 0, - DeviceName_Avpc = 1, - DeviceName_Dc = 2, - DeviceName_Dcb = 3, - DeviceName_Hc = 4, - DeviceName_Hda = 5, - DeviceName_Isp2 = 6, - DeviceName_MsencNvenc = 7, - DeviceName_Nv = 8, - DeviceName_Nv2 = 9, - DeviceName_Ppcs = 10, - DeviceName_Sata = 11, - DeviceName_Vi = 12, - DeviceName_Vic = 13, - DeviceName_XusbHost = 14, - DeviceName_XusbDev = 15, - DeviceName_Tsec = 16, - DeviceName_Ppcs1 = 17, - DeviceName_Dc1 = 18, - DeviceName_Sdmmc1a = 19, - DeviceName_Sdmmc2a = 20, - DeviceName_Sdmmc3a = 21, - DeviceName_Sdmmc4a = 22, - DeviceName_Isp2b = 23, - DeviceName_Gpu = 24, - DeviceName_Gpub = 25, - DeviceName_Ppcs2 = 26, - DeviceName_Nvdec = 27, - DeviceName_Ape = 28, - DeviceName_Se = 29, - DeviceName_Nvjpg = 30, - DeviceName_Hc1 = 31, - DeviceName_Se1 = 32, - DeviceName_Axiap = 33, - DeviceName_Etr = 34, - DeviceName_Tsecb = 35, - DeviceName_Tsec1 = 36, - DeviceName_Tsecb1 = 37, - DeviceName_Nvdec1 = 38, - - DeviceName_Count, - }; - -} diff --git a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp deleted file mode 100644 index 55d95f0..0000000 --- a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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::svc::board::nintendo_switch { - - 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 1903506..31e91b3 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 c7bba81..5ab60ee 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