kern: switch->nx, implement sleep manager init

This commit is contained in:
Michael Scire 2020-02-14 19:58:57 -08:00
parent 20b5268e90
commit 2c496e94d5
30 changed files with 374 additions and 55 deletions

View file

@ -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_SETTINGS +=
export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_CXXFLAGS +=

View file

@ -24,11 +24,11 @@ export ATMOSPHERE_ASFLAGS :=
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
export ATMOSPHERE_ARCH_DIR := arch/arm64 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_OS_DIR := os/horizon
export ATMOSPHERE_ARCH_NAME := arm64 export ATMOSPHERE_ARCH_NAME := arm64
export ATMOSPHERE_BOARD_NAME := nintendo_switch export ATMOSPHERE_BOARD_NAME := nintendo_nx
export ATMOSPHERE_OS_NAME := horizon export ATMOSPHERE_OS_NAME := horizon
endif endif

View file

@ -30,6 +30,7 @@
/* Core pre-initialization includes. */ /* Core pre-initialization includes. */
#include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_select_system_control.hpp> #include <mesosphere/kern_select_system_control.hpp>
#include <mesosphere/kern_k_target_system.hpp>
/* Initialization headers. */ /* Initialization headers. */
#include <mesosphere/init/kern_init_elf.hpp> #include <mesosphere/init/kern_init_elf.hpp>

View file

@ -27,7 +27,7 @@ namespace ams::kern::arch::arm64::cpu {
#error "Unknown CPU for cache line sizes" #error "Unknown CPU for cache line sizes"
#endif #endif
#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
constexpr inline size_t NumCores = 4; constexpr inline size_t NumCores = 4;
#else #else
#error "Unknown Board for cpu::NumCores" #error "Unknown Board for cpu::NumCores"

View file

@ -28,7 +28,7 @@ namespace ams::kern::arch::arm64 {
KInterruptName_PerformanceCounter = 8, KInterruptName_PerformanceCounter = 8,
/* PPIs */ /* PPIs */
#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
KInterruptName_VirtualMaintenance = 25, KInterruptName_VirtualMaintenance = 25,
KInterruptName_HypervisorTimer = 26, KInterruptName_HypervisorTimer = 26,
KInterruptName_VirtualTimer = 27, KInterruptName_VirtualTimer = 27,
@ -38,7 +38,7 @@ namespace ams::kern::arch::arm64 {
KInterruptName_LegacyNIrq = 31, KInterruptName_LegacyNIrq = 31,
#endif #endif
#if defined(ATMOSPHERE_BOARD_NINTENDO_SWITCH) #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
KInterruptName_MemoryController = 109, KInterruptName_MemoryController = 109,
#endif #endif
}; };

View file

@ -35,7 +35,7 @@ namespace ams::kern::arch::arm64 {
BlockType_L3ContiguousBlock, BlockType_L3ContiguousBlock,
BlockType_L2Block, BlockType_L2Block,
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
BlockType_L2TegraSmmuBlock, BlockType_L2TegraSmmuBlock,
#endif #endif
@ -48,14 +48,14 @@ namespace ams::kern::arch::arm64 {
static_assert(L3BlockSize == PageSize); static_assert(L3BlockSize == PageSize);
static constexpr size_t ContiguousPageSize = L3ContiguousBlockSize; static constexpr size_t ContiguousPageSize = L3ContiguousBlockSize;
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
static constexpr size_t L2TegraSmmuBlockSize = 2 * L2BlockSize; static constexpr size_t L2TegraSmmuBlockSize = 2 * L2BlockSize;
#endif #endif
static constexpr size_t BlockSizes[BlockType_Count] = { static constexpr size_t BlockSizes[BlockType_Count] = {
[BlockType_L3Block] = L3BlockSize, [BlockType_L3Block] = L3BlockSize,
[BlockType_L3ContiguousBlock] = L3ContiguousBlockSize, [BlockType_L3ContiguousBlock] = L3ContiguousBlockSize,
[BlockType_L2Block] = L2BlockSize, [BlockType_L2Block] = L2BlockSize,
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
[BlockType_L2TegraSmmuBlock] = L2TegraSmmuBlockSize, [BlockType_L2TegraSmmuBlock] = L2TegraSmmuBlockSize,
#endif #endif
[BlockType_L2ContiguousBlock] = L2ContiguousBlockSize, [BlockType_L2ContiguousBlock] = L2ContiguousBlockSize,
@ -71,7 +71,7 @@ namespace ams::kern::arch::arm64 {
case L3BlockSize: return BlockType_L3Block; case L3BlockSize: return BlockType_L3Block;
case L3ContiguousBlockSize: return BlockType_L3ContiguousBlock; case L3ContiguousBlockSize: return BlockType_L3ContiguousBlock;
case L2BlockSize: return BlockType_L2Block; case L2BlockSize: return BlockType_L2Block;
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
case L2TegraSmmuBlockSize: return BlockType_L2TegraSmmuBlock; case L2TegraSmmuBlockSize: return BlockType_L2TegraSmmuBlock;
#endif #endif
case L2ContiguousBlockSize: return BlockType_L2ContiguousBlock; case L2ContiguousBlockSize: return BlockType_L2ContiguousBlock;

View file

@ -34,43 +34,62 @@ namespace ams::kern::arch::arm64 {
static constexpr size_t LevelBits = 9; static constexpr size_t LevelBits = 9;
static_assert(NumLevels > 0); static_assert(NumLevels > 0);
static constexpr size_t AddressBits = (NumLevels - 1) * LevelBits + PageBits; template<size_t Offset, size_t Count>
static_assert(AddressBits <= BITSIZEOF(u64)); static constexpr ALWAYS_INLINE u64 GetBits(u64 value) {
static constexpr size_t AddressSpaceSize = (1ull << AddressBits); return (value >> Offset) & ((1ul << Count) - 1);
}
template<size_t Offset, size_t Count>
constexpr ALWAYS_INLINE u64 SelectBits(u64 value) {
return value & (((1ul << Count) - 1) << Offset);
}
static constexpr ALWAYS_INLINE uintptr_t GetL0Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 0), LevelBits>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetL1Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 1), LevelBits>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetL2Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 2), LevelBits>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetL3Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 3), LevelBits>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1)>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2)>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3)>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetContiguousL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1) + 4>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetContiguousL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2) + 4>(GetInteger(addr)); }
static constexpr ALWAYS_INLINE uintptr_t GetContiguousL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3) + 4>(GetInteger(addr)); }
private: private:
L1PageTableEntry *table; L1PageTableEntry *table;
bool is_kernel; bool is_kernel;
u32 num_entries; u32 num_entries;
public: 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); return table + index * sizeof(PageTableEntry);
} }
ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) { ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) const {
return GetPointer<L1PageTableEntry>(GetTableEntry(KVirtualAddress(this->table), (GetInteger(address) >> (PageBits + LevelBits * 2)) & (this->num_entries - 1))); return GetPointer<L1PageTableEntry>(GetTableEntry(KVirtualAddress(this->table), GetL1Index(address) & (this->num_entries - 1)));
} }
ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) { ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) const {
return GetPointer<L2PageTableEntry>(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 1)) & ((1ul << LevelBits) - 1))); return GetPointer<L2PageTableEntry>(GetTableEntry(table, GetL2Index(address)));
} }
ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KProcessAddress address) { ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KProcessAddress address) const {
return GetL2EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address); return GetL2EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
} }
ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) { ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) const {
return GetPointer<L3PageTableEntry>(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 0)) & ((1ul << LevelBits) - 1))); return GetPointer<L3PageTableEntry>(GetTableEntry(table, GetL3Index(address)));
} }
ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KProcessAddress address) { ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KProcessAddress address) const {
return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address); return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
} }
public: public:
constexpr KPageTableImpl() : table(), is_kernel(), num_entries() { /* ... */ } constexpr KPageTableImpl() : table(), is_kernel(), num_entries() { /* ... */ }
NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end); NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end);
L1PageTableEntry *Finalize(); L1PageTableEntry *Finalize();
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const;
}; };
} }

View file

@ -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) { 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); 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);
}
}; };
} }

View file

@ -16,7 +16,7 @@
#pragma once #pragma once
#include <mesosphere/kern_common.hpp> #include <mesosphere/kern_common.hpp>
namespace ams::kern { namespace ams::kern::board::nintendo::nx {
class KSystemControl { class KSystemControl {
public: public:
@ -37,14 +37,16 @@ namespace ams::kern {
}; };
public: public:
/* Initialization. */ /* Initialization. */
static NOINLINE void Initialize(); static NOINLINE void InitializePhase1();
static NOINLINE void InitializePhase2();
static NOINLINE u32 GetInitialProcessBinaryPool(); static NOINLINE u32 GetInitialProcessBinaryPool();
/* Randomness. */ /* Randomness. */
static void GenerateRandomBytes(void *dst, size_t size); static void GenerateRandomBytes(void *dst, size_t size);
static u64 GenerateRandomRange(u64 min, u64 max); static u64 GenerateRandomRange(u64 min, u64 max);
/* Panic. */ /* Power management. */
static void SleepSystem();
static NORETURN void StopSystem(); static NORETURN void StopSystem();
}; };

View file

@ -32,7 +32,7 @@ namespace ams::kern {
#ifndef MESOSPHERE_DEBUG_LOG_SELECTED #ifndef MESOSPHERE_DEBUG_LOG_SELECTED
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#define MESOSPHERE_DEBUG_LOG_USE_UART_C #define MESOSPHERE_DEBUG_LOG_USE_UART_C
#else #else
#error "Unknown board for Default Debug Log Source" #error "Unknown board for Default Debug Log Source"

View file

@ -15,12 +15,12 @@
*/ */
#pragma once #pragma once
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_ARCH_ARM64
#include <mesosphere/arch/arm64/kern_k_exception_context.hpp> #include <mesosphere/arch/arm64/kern_k_exception_context.hpp>
namespace ams::kern { namespace ams::kern {
using ams::kern::arch::arm64::KExceptionContext; using ams::kern::arch::arm64::KExceptionContext;
} }
#else #else
#error "Unknown board for KExceptionContext" #error "Unknown architecture for KExceptionContext"
#endif #endif

View file

@ -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); 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: 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) { 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); return this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm);
} }

View file

@ -15,11 +15,10 @@
*/ */
#pragma once #pragma once
#include <mesosphere/kern_common.hpp> #include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_select_system_control.hpp>
namespace ams::kern { namespace ams::kern {
class KSystemControl;
class KTargetSystem { class KTargetSystem {
private: private:
friend class KSystemControl; friend class KSystemControl;

View file

@ -15,12 +15,12 @@
*/ */
#pragma once #pragma once
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_ARCH_ARM64
#include <mesosphere/arch/arm64/kern_k_thread_context.hpp> #include <mesosphere/arch/arm64/kern_k_thread_context.hpp>
namespace ams::kern { namespace ams::kern {
using ams::kern::arch::arm64::KThreadContext; using ams::kern::arch::arm64::KThreadContext;
} }
#else #else
#error "Unknown board for KThreadContext" #error "Unknown architecture for KThreadContext"
#endif #endif

View file

@ -15,10 +15,14 @@
*/ */
#pragma once #pragma once
#include <mesosphere/kern_common.hpp> #include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_target_system.hpp>
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#include <mesosphere/board/nintendo/switch/kern_k_system_control.hpp> #include <mesosphere/board/nintendo/nx/kern_k_system_control.hpp>
namespace ams::kern {
using ams::kern::board::nintendo::nx::KSystemControl;
}
#else #else
#error "Unknown board for KSystemControl" #error "Unknown board for KSystemControl"
#endif #endif

View file

@ -20,11 +20,55 @@ namespace ams::kern::arch::arm64 {
void KPageTableImpl::InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end) { void KPageTableImpl::InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end) {
this->table = static_cast<L1PageTableEntry *>(tb); this->table = static_cast<L1PageTableEntry *>(tb);
this->is_kernel = true; 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() { L1PageTableEntry *KPageTableImpl::Finalize() {
return this->table; 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;
}
} }

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>
#include "kern_k_sleep_manager.hpp"
#include "kern_secure_monitor.hpp"
namespace ams::kern::board::nintendo::nx {
namespace {
/* Struct representing registers saved on wake/sleep. */
class SavedSystemRegisters {
private:
u64 ttbr0_el1;
u64 tcr_el1;
u64 elr_el1;
u64 sp_el0;
u64 spsr_el1;
u64 daif;
u64 cpacr_el1;
u64 vbar_el1;
u64 csselr_el1;
u64 cntp_ctl_el0;
u64 cntp_cval_el0;
u64 cntkctl_el1;
u64 tpidr_el0;
u64 tpidrro_el0;
u64 mdscr_el1;
u64 contextidr_el1;
u64 dbgwcrN_el1[16];
u64 dbgwvrN_el1[16];
u64 dbgbcrN_el1[16];
u64 dbgbvrN_el1[16];
u64 pmccfiltr_el0;
u64 pmccntr_el0;
u64 pmcntenset_el0;
u64 pmcr_el0;
u64 pmevcntrN_el0[31];
u64 pmevtyperN_el0[31];
u64 pmcntenset_el1;
u64 pmovsset_el0;
u64 pmselr_el0;
u64 pmuserenr_el0;
public:
void Save();
void Restore() const;
};
constexpr s32 SleepManagerThreadPriority = 2;
/* Globals for sleep/wake. */
u64 g_sleep_target_cores;
KLightLock g_request_lock;
KLightLock g_cv_lock;
KLightConditionVariable g_cv;
KPhysicalAddress g_sleep_buffer_phys_addrs[cpu::NumCores];
alignas(16) u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)];
SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {};
}
void KSleepManager::Initialize() {
/* Create a sleep manager thread for each core. */
for (size_t core_id = 0; core_id < cpu::NumCores; core_id++) {
/* Reserve a thread from the system limit. */
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_ThreadCountMax, 1));
/* Create a new thread. */
KThread *new_thread = KThread::Create();
MESOSPHERE_ABORT_UNLESS(new_thread != nullptr);
/* Launch the new thread. */
MESOSPHERE_R_ABORT_UNLESS(KThread::InitializeKernelThread(new_thread, KSleepManager::ProcessRequests, reinterpret_cast<uintptr_t>(g_sleep_buffers[core_id]), SleepManagerThreadPriority, static_cast<s32>(core_id)));
/* Register the new thread. */
KThread::Register(new_thread);
/* Run the thread. */
new_thread->Run();
}
}
void KSleepManager::SleepSystem() {
/* Ensure device mappings are not modified during sleep. */
MESOSPHERE_TODO("KDevicePageTable::Lock();");
ON_SCOPE_EXIT { MESOSPHERE_TODO("KDevicePageTable::Unlock();"); };
/* Request that the system sleep. */
{
KScopedLightLock lk(g_request_lock);
/* Signal the manager to sleep on all cores. */
{
KScopedLightLock lk(g_cv_lock);
MESOSPHERE_ABORT_UNLESS(g_sleep_target_cores == 0);
g_sleep_target_cores = (1ul << (cpu::NumCores - 1));
g_cv.Broadcast();
while (g_sleep_target_cores != 0) {
g_cv.Wait(std::addressof(g_cv_lock));
}
}
}
}
void KSleepManager::ProcessRequests(uintptr_t buffer) {
const s32 core_id = GetCurrentCoreId();
KPhysicalAddress resume_entry_phys_addr = Null<KPhysicalAddress>;
/* Get the physical addresses we'll need. */
{
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(g_sleep_buffer_phys_addrs[core_id]), KProcessAddress(buffer)));
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(resume_entry_phys_addr), KProcessAddress(&::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry)));
}
const KPhysicalAddress sleep_buffer_phys_addr = g_sleep_buffer_phys_addrs[core_id];
const u64 target_core_mask = (1ul << core_id);
/* Loop, processing sleep when requested. */
while (true) {
/* Wait for a request. */
{
KScopedLightLock lk(g_cv_lock);
while (!(g_sleep_target_cores & target_core_mask)) {
g_cv.Wait(std::addressof(g_cv_lock));
}
}
MESOSPHERE_TODO("Implement Sleep/Wake");
(void)(g_sleep_system_registers[core_id]);
(void)(sleep_buffer_phys_addr);
/* Signal request completed. */
{
KScopedLightLock lk(g_cv_lock);
g_sleep_target_cores &= ~target_core_mask;
if (g_sleep_target_cores == 0) {
g_cv.Broadcast();
}
}
}
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere.hpp>
namespace ams::kern::board::nintendo::nx {
class KSleepManager {
private:
static void CpuSleepHandler(uintptr_t arg, uintptr_t entry);
static void ResumeEntry(uintptr_t arg);
static void ProcessRequests(uintptr_t buffer);
public:
static void Initialize();
static void SleepSystem();
};
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry(uintptr_t arg) */
.section .text._ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, "ax", %progbits
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function
_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
/* TODO: Implement a real function here. */
brk 1000

View file

@ -15,14 +15,20 @@
*/ */
#include <mesosphere.hpp> #include <mesosphere.hpp>
#include "kern_secure_monitor.hpp" #include "kern_secure_monitor.hpp"
#include "kern_k_sleep_manager.hpp"
namespace ams::kern { namespace ams::kern::board::nintendo::nx {
namespace { namespace {
/* Global variables for panic. */ /* Global variables for panic. */
bool g_call_smc_on_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. */ /* Global variables for randomness. */
/* Nintendo uses std::mt19937_t for randomness. */ /* Nintendo uses std::mt19937_t for randomness. */
/* To save space (and because mt19337_t isn't secure anyway), */ /* To save space (and because mt19337_t isn't secure anyway), */
@ -195,7 +201,7 @@ namespace ams::kern {
} }
/* System Initialization. */ /* System Initialization. */
void KSystemControl::Initialize() { void KSystemControl::InitializePhase1() {
/* Set IsDebugMode. */ /* Set IsDebugMode. */
{ {
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
@ -250,6 +256,21 @@ namespace ams::kern {
} }
} }
void KSystemControl::InitializePhase2() {
/* Initialize the sleep manager. */
KSleepManager::Initialize();
/* Reserve secure applet memory. */
{
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null<KVirtualAddress>);
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletReservedMemorySize));
constexpr auto SecureAppletAllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
g_secure_applet_memory_address = Kernel::GetMemoryManager().AllocateContinuous(SecureAppletReservedMemorySize / PageSize, 1, SecureAppletAllocateOption);
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>);
}
}
u32 KSystemControl::GetInitialProcessBinaryPool() { u32 KSystemControl::GetInitialProcessBinaryPool() {
return KMemoryManager::Pool_Application; return KMemoryManager::Pool_Application;
} }
@ -274,6 +295,11 @@ namespace ams::kern {
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator); return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
} }
void KSystemControl::SleepSystem() {
MESOSPHERE_LOG("SleepSystem() was called\n");
KSleepManager::SleepSystem();
}
void KSystemControl::StopSystem() { void KSystemControl::StopSystem() {
if (g_call_smc_on_panic) { if (g_call_smc_on_panic) {
/* Display a panic screen via secure monitor. */ /* Display a panic screen via secure monitor. */

View file

@ -16,7 +16,7 @@
#include <mesosphere.hpp> #include <mesosphere.hpp>
#include "kern_secure_monitor.hpp" #include "kern_secure_monitor.hpp"
namespace ams::kern::smc { namespace ams::kern::board::nintendo::nx::smc {
namespace { namespace {

View file

@ -16,7 +16,7 @@
#pragma once #pragma once
#include <mesosphere.hpp> #include <mesosphere.hpp>
namespace ams::kern::smc { namespace ams::kern::board::nintendo::nx::smc {
/* Types. */ /* Types. */
enum MemorySize { enum MemorySize {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <mesosphere.hpp> #include <mesosphere.hpp>
#include "../../../kern_debug_log_impl.hpp" #include "kern_debug_log_impl.hpp"
namespace ams::kern { namespace ams::kern {

View file

@ -46,8 +46,8 @@ namespace ams::kern {
}); });
if (core_id == 0) { if (core_id == 0) {
/* Initialize KSystemControl. */ /* Initialize the carveout and the system resource limit. */
KSystemControl::Initialize(); KSystemControl::InitializePhase1();
/* Initialize the memory manager and the KPageBuffer slabheap. */ /* Initialize the memory manager and the KPageBuffer slabheap. */
{ {
@ -107,9 +107,11 @@ namespace ams::kern {
/* Perform more core-0 specific initialization. */ /* Perform more core-0 specific initialization. */
if (core_id == 0) { 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); 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();"); MESOSPHERE_TODO("KDeviceAddressSpace::Initialize();");

View file

@ -52,7 +52,7 @@
#endif /* ATMOSPHERE_IS_STRATOSPHERE */ #endif /* ATMOSPHERE_IS_STRATOSPHERE */
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#ifdef ATMOSPHERE_IS_STRATOSPHERE #ifdef ATMOSPHERE_IS_STRATOSPHERE
@ -70,7 +70,7 @@
#error "Unsupported board" #error "Unsupported board"
#endif /* ATMOSPHERE_BOARD_NINTENDO_SWITCH */ #endif /* ATMOSPHERE_BOARD_NINTENDO_NX */
/* Atmosphere meta. */ /* Atmosphere meta. */
#include "ams_version.h" #include "ams_version.h"

View file

@ -16,7 +16,7 @@
#pragma once #pragma once
#include <vapours/svc/svc_types_common.hpp> #include <vapours/svc/svc_types_common.hpp>
namespace ams::svc::board::nintendo_switch { namespace ams::svc::board::nintendo::nx {
enum DeviceName { enum DeviceName {
DeviceName_Afi = 0, DeviceName_Afi = 0,

View file

@ -16,7 +16,7 @@
#pragma once #pragma once
#include <vapours/svc/svc_types_common.hpp> #include <vapours/svc/svc_types_common.hpp>
namespace ams::svc::board::nintendo_switch { namespace ams::svc::board::nintendo::nx {
constexpr inline const s64 TicksPerSecond = 19'200'000; constexpr inline const s64 TicksPerSecond = 19'200'000;

View file

@ -17,11 +17,11 @@
#pragma once #pragma once
#include "svc_common.hpp" #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 { namespace ams::svc {
using namespace ams::svc::board::nintendo_switch; using namespace ams::svc::board::nintendo::nx;
} }
#else #else

View file

@ -17,11 +17,11 @@
#pragma once #pragma once
#include "svc_common.hpp" #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 { namespace ams::svc {
using namespace ams::svc::board::nintendo_switch; using namespace ams::svc::board::nintendo::nx;
} }
#else #else