diff --git a/libraries/config/board/nintendo/switch/board.mk b/libraries/config/board/nintendo/nx/board.mk similarity index 60% rename from libraries/config/board/nintendo/switch/board.mk rename to libraries/config/board/nintendo/nx/board.mk index facdf9632..0a7acfca7 100644 --- a/libraries/config/board/nintendo/switch/board.mk +++ b/libraries/config/board/nintendo/nx/board.mk @@ -1,4 +1,4 @@ -export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_SWITCH -D__SWITCH__ +export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_NX -D__SWITCH__ export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += diff --git a/libraries/config/common.mk b/libraries/config/common.mk index e71dc1500..7e1c84ab3 100644 --- a/libraries/config/common.mk +++ b/libraries/config/common.mk @@ -24,11 +24,11 @@ export ATMOSPHERE_ASFLAGS := ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) export ATMOSPHERE_ARCH_DIR := arch/arm64 -export ATMOSPHERE_BOARD_DIR := board/nintendo/switch +export ATMOSPHERE_BOARD_DIR := board/nintendo/nx export ATMOSPHERE_OS_DIR := os/horizon export ATMOSPHERE_ARCH_NAME := arm64 -export ATMOSPHERE_BOARD_NAME := nintendo_switch +export ATMOSPHERE_BOARD_NAME := nintendo_nx export ATMOSPHERE_OS_NAME := horizon endif diff --git a/libraries/libmesosphere/include/mesosphere.hpp b/libraries/libmesosphere/include/mesosphere.hpp index 85a4bc3a6..b09ff06aa 100644 --- a/libraries/libmesosphere/include/mesosphere.hpp +++ b/libraries/libmesosphere/include/mesosphere.hpp @@ -30,6 +30,7 @@ /* Core pre-initialization includes. */ #include #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 1ae915f1a..329005051 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp @@ -27,7 +27,7 @@ namespace ams::kern::arch::arm64::cpu { #error "Unknown CPU for cache line sizes" #endif -#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) constexpr inline size_t NumCores = 4; #else #error "Unknown Board for cpu::NumCores" diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp index 5902b11d4..97900023d 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp @@ -28,7 +28,7 @@ namespace ams::kern::arch::arm64 { KInterruptName_PerformanceCounter = 8, /* PPIs */ - #if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) KInterruptName_VirtualMaintenance = 25, KInterruptName_HypervisorTimer = 26, KInterruptName_VirtualTimer = 27, @@ -38,7 +38,7 @@ namespace ams::kern::arch::arm64 { KInterruptName_LegacyNIrq = 31, #endif - #if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) KInterruptName_MemoryController = 109, #endif }; diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp index fdf59b815..0975d658d 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp @@ -35,7 +35,7 @@ namespace ams::kern::arch::arm64 { BlockType_L3ContiguousBlock, BlockType_L2Block, -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX BlockType_L2TegraSmmuBlock, #endif @@ -48,14 +48,14 @@ namespace ams::kern::arch::arm64 { static_assert(L3BlockSize == PageSize); static constexpr size_t ContiguousPageSize = L3ContiguousBlockSize; -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX static constexpr size_t L2TegraSmmuBlockSize = 2 * L2BlockSize; #endif static constexpr size_t BlockSizes[BlockType_Count] = { [BlockType_L3Block] = L3BlockSize, [BlockType_L3ContiguousBlock] = L3ContiguousBlockSize, [BlockType_L2Block] = L2BlockSize, -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX [BlockType_L2TegraSmmuBlock] = L2TegraSmmuBlockSize, #endif [BlockType_L2ContiguousBlock] = L2ContiguousBlockSize, @@ -71,7 +71,7 @@ namespace ams::kern::arch::arm64 { case L3BlockSize: return BlockType_L3Block; case L3ContiguousBlockSize: return BlockType_L3ContiguousBlock; case L2BlockSize: return BlockType_L2Block; -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX case L2TegraSmmuBlockSize: return BlockType_L2TegraSmmuBlock; #endif case L2ContiguousBlockSize: return BlockType_L2ContiguousBlock; diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp index 113c4777e..2b5665141 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp @@ -34,43 +34,62 @@ namespace ams::kern::arch::arm64 { static constexpr size_t LevelBits = 9; static_assert(NumLevels > 0); - static constexpr size_t AddressBits = (NumLevels - 1) * LevelBits + PageBits; - static_assert(AddressBits <= BITSIZEOF(u64)); - static constexpr size_t AddressSpaceSize = (1ull << AddressBits); + template + 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 c33069681..6596e70fb 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp @@ -34,6 +34,10 @@ namespace ams::kern::arch::arm64 { Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { return this->page_table.MapPages(out_addr, num_pages, alignment, phys_addr, region_start, region_num_pages, state, perm); } + + bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const { + return this->page_table.GetPhysicalAddress(out, address); + } }; } diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp similarity index 89% rename from libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp rename to libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp index 3572d0897..e14c73474 100644 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/switch/kern_k_system_control.hpp +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp @@ -16,7 +16,7 @@ #pragma once #include -namespace ams::kern { +namespace ams::kern::board::nintendo::nx { class KSystemControl { public: @@ -37,14 +37,16 @@ namespace ams::kern { }; public: /* Initialization. */ - static NOINLINE void Initialize(); + static NOINLINE void InitializePhase1(); + static NOINLINE void InitializePhase2(); static NOINLINE u32 GetInitialProcessBinaryPool(); /* Randomness. */ static void GenerateRandomBytes(void *dst, size_t size); static u64 GenerateRandomRange(u64 min, u64 max); - /* Panic. */ + /* Power management. */ + static void SleepSystem(); static NORETURN void StopSystem(); }; diff --git a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp index bb4d4e988..85a707904 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp @@ -32,7 +32,7 @@ namespace ams::kern { #ifndef MESOSPHERE_DEBUG_LOG_SELECTED - #ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH + #ifdef ATMOSPHERE_BOARD_NINTENDO_NX #define MESOSPHERE_DEBUG_LOG_USE_UART_C #else #error "Unknown board for Default Debug Log Source" diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp index aceefcd8e..e07ce69eb 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp @@ -15,12 +15,12 @@ */ #pragma once -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_ARCH_ARM64 #include namespace ams::kern { using ams::kern::arch::arm64::KExceptionContext; } #else - #error "Unknown board for KExceptionContext" + #error "Unknown architecture for KExceptionContext" #endif diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index f2a3c3053..68f5ab34a 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -196,6 +196,10 @@ namespace ams::kern { NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm); public: + bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const { + return this->GetImpl().GetPhysicalAddress(out, virt_addr); + } + Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { return this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp index 123595b4c..2134f830f 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp @@ -15,11 +15,10 @@ */ #pragma once #include +#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 a675d5184..25df4ae70 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread_context.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread_context.hpp @@ -15,12 +15,12 @@ */ #pragma once -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_ARCH_ARM64 #include namespace ams::kern { using ams::kern::arch::arm64::KThreadContext; } #else - #error "Unknown board for KThreadContext" + #error "Unknown architecture for KThreadContext" #endif diff --git a/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp b/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp index 75c0a4002..5d4890d67 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp @@ -15,10 +15,14 @@ */ #pragma once #include -#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 a97266d3c..368c0299d 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp @@ -20,11 +20,55 @@ namespace ams::kern::arch::arm64 { void KPageTableImpl::InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end) { this->table = static_cast(tb); this->is_kernel = true; - this->num_entries = util::AlignUp(end - start, AddressSpaceSize) / AddressSpaceSize; + this->num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize; } L1PageTableEntry *KPageTableImpl::Finalize() { return this->table; } + bool KPageTableImpl::GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const { + /* Validate that we can read the actual entry. */ + const size_t l0_index = GetL0Index(address); + const size_t l1_index = GetL1Index(address); + if (this->is_kernel) { + /* Kernel entries must be accessed via TTBR1. */ + if ((l0_index != MaxPageTableEntries - 1) || (l1_index < MaxPageTableEntries - this->num_entries)) { + return false; + } + } else { + /* User entries must be accessed with TTBR0. */ + if ((l0_index != 0) || l1_index >= this->num_entries) { + return false; + } + } + + /* Try to get from l1 table. */ + const L1PageTableEntry *l1_entry = this->GetL1Entry(address); + if (l1_entry->IsBlock()) { + *out = l1_entry->GetBlock() + GetL1Offset(address); + return true; + } else if (!l1_entry->IsTable()) { + return false; + } + + /* Try to get from l2 table. */ + const L2PageTableEntry *l2_entry = this->GetL2Entry(l1_entry, address); + if (l2_entry->IsBlock()) { + *out = l2_entry->GetBlock() + GetL2Offset(address); + return true; + } else if (!l2_entry->IsTable()) { + return false; + } + + /* Try to get from l3 table. */ + const L3PageTableEntry *l3_entry = this->GetL3Entry(l2_entry, address); + if (l3_entry->IsBlock()) { + *out = l3_entry->GetBlock() + GetL3Offset(address); + return true; + } + + return false; + } + } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp new file mode 100644 index 000000000..3846b1752 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#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 000000000..1cc500c4d --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#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 000000000..1c4a014cd --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager_asm.s @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry(uintptr_t arg) */ +.section .text._ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, "ax", %progbits +.global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm +.type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function +_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm: + /* TODO: Implement a real function here. */ + brk 1000 \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp similarity index 89% rename from libraries/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp rename to libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index 4e653159d..c0c6cd808 100644 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_system_control.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -15,14 +15,20 @@ */ #include #include "kern_secure_monitor.hpp" +#include "kern_k_sleep_manager.hpp" -namespace ams::kern { +namespace ams::kern::board::nintendo::nx { namespace { /* Global variables for panic. */ bool g_call_smc_on_panic; + /* Global variables for secure memory. */ + constexpr size_t SecureAppletReservedMemorySize = 4_MB; + KVirtualAddress g_secure_applet_memory_address; + + /* Global variables for randomness. */ /* Nintendo uses std::mt19937_t for randomness. */ /* To save space (and because mt19337_t isn't secure anyway), */ @@ -195,7 +201,7 @@ namespace ams::kern { } /* System Initialization. */ - void KSystemControl::Initialize() { + void KSystemControl::InitializePhase1() { /* Set IsDebugMode. */ { KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); @@ -250,6 +256,21 @@ namespace ams::kern { } } + void KSystemControl::InitializePhase2() { + /* Initialize the sleep manager. */ + KSleepManager::Initialize(); + + /* Reserve secure applet memory. */ + { + MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null); + 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; } @@ -274,6 +295,11 @@ namespace ams::kern { return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator); } + void KSystemControl::SleepSystem() { + MESOSPHERE_LOG("SleepSystem() was called\n"); + KSleepManager::SleepSystem(); + } + void KSystemControl::StopSystem() { if (g_call_smc_on_panic) { /* Display a panic screen via secure monitor. */ diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp similarity index 99% rename from libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp rename to libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp index 7c49443d6..d3797d7ea 100644 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp @@ -16,7 +16,7 @@ #include #include "kern_secure_monitor.hpp" -namespace ams::kern::smc { +namespace ams::kern::board::nintendo::nx::smc { namespace { diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp similarity index 98% rename from libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp rename to libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp index 14c1fc38e..dcf1c4dca 100644 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_secure_monitor.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp @@ -16,7 +16,7 @@ #pragma once #include -namespace ams::kern::smc { +namespace ams::kern::board::nintendo::nx::smc { /* Types. */ enum MemorySize { diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp similarity index 98% rename from libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp rename to libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp index 8985447cf..e90cbc70f 100644 --- a/libraries/libmesosphere/source/board/nintendo/switch/kern_debug_log_impl.cpp +++ b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #include -#include "../../../kern_debug_log_impl.hpp" +#include "kern_debug_log_impl.hpp" namespace ams::kern { diff --git a/libraries/libmesosphere/source/board/nintendo/switch/kern_k_memory_layout.board.nintendo_switch.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp similarity index 100% rename from libraries/libmesosphere/source/board/nintendo/switch/kern_k_memory_layout.board.nintendo_switch.cpp rename to libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp diff --git a/libraries/libmesosphere/source/kern_main.cpp b/libraries/libmesosphere/source/kern_main.cpp index bafa88c08..9d06110a5 100644 --- a/libraries/libmesosphere/source/kern_main.cpp +++ b/libraries/libmesosphere/source/kern_main.cpp @@ -46,8 +46,8 @@ namespace ams::kern { }); if (core_id == 0) { - /* Initialize KSystemControl. */ - KSystemControl::Initialize(); + /* Initialize the carveout and the system resource limit. */ + KSystemControl::InitializePhase1(); /* Initialize the memory manager and the KPageBuffer slabheap. */ { @@ -107,9 +107,11 @@ namespace ams::kern { /* Perform more core-0 specific initialization. */ if (core_id == 0) { + /* Initialize the exit worker manager, so that threads and processes may exit cleanly. */ Kernel::GetWorkerTaskManager(KWorkerTaskManager::WorkerType_Exit).Initialize(KWorkerTaskManager::WorkerType_Exit, KWorkerTaskManager::ExitWorkerPriority); - MESOSPHERE_TODO("KSystemControl::InitializeSleepManagerAndAppletSecureMemory();"); + /* Setup so that we may sleep later, and reserve memory for secure applets. */ + KSystemControl::InitializePhase2(); MESOSPHERE_TODO("KDeviceAddressSpace::Initialize();"); diff --git a/libraries/libvapours/include/vapours/includes.hpp b/libraries/libvapours/include/vapours/includes.hpp index 7e1bc682b..64ac45ee2 100644 --- a/libraries/libvapours/include/vapours/includes.hpp +++ b/libraries/libvapours/include/vapours/includes.hpp @@ -52,7 +52,7 @@ #endif /* ATMOSPHERE_IS_STRATOSPHERE */ -#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH +#ifdef ATMOSPHERE_BOARD_NINTENDO_NX #ifdef ATMOSPHERE_IS_STRATOSPHERE @@ -70,7 +70,7 @@ #error "Unsupported board" -#endif /* ATMOSPHERE_BOARD_NINTENDO_SWITCH */ +#endif /* ATMOSPHERE_BOARD_NINTENDO_NX */ /* Atmosphere meta. */ #include "ams_version.h" diff --git a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp similarity index 97% rename from libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp rename to libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp index f1175d773..fb289dd83 100644 --- a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_device_name.hpp +++ b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp @@ -16,7 +16,7 @@ #pragma once #include -namespace ams::svc::board::nintendo_switch { +namespace ams::svc::board::nintendo::nx { enum DeviceName { DeviceName_Afi = 0, diff --git a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp similarity index 94% rename from libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp rename to libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp index 55d95f04e..8b270b125 100644 --- a/libraries/libvapours/include/vapours/svc/board/nintendo/switch/svc_hardware_constants.hpp +++ b/libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp @@ -16,7 +16,7 @@ #pragma once #include -namespace ams::svc::board::nintendo_switch { +namespace ams::svc::board::nintendo::nx { constexpr inline const s64 TicksPerSecond = 19'200'000; diff --git a/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp b/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp index 190350676..31e91b351 100644 --- a/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp @@ -17,11 +17,11 @@ #pragma once #include "svc_common.hpp" -#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) - #include "board/nintendo/switch/svc_device_name.hpp" + #include "board/nintendo/nx/svc_device_name.hpp" namespace ams::svc { - using namespace ams::svc::board::nintendo_switch; + using namespace ams::svc::board::nintendo::nx; } #else diff --git a/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp b/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp index c7bba8105..5ab60ee5d 100644 --- a/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp @@ -17,11 +17,11 @@ #pragma once #include "svc_common.hpp" -#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) - #include "board/nintendo/switch/svc_hardware_constants.hpp" + #include "board/nintendo/nx/svc_hardware_constants.hpp" namespace ams::svc { - using namespace ams::svc::board::nintendo_switch; + using namespace ams::svc::board::nintendo::nx; } #else