mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
kern: switch->nx, implement sleep manager init
This commit is contained in:
parent
20b5268e90
commit
2c496e94d5
30 changed files with 374 additions and 55 deletions
|
@ -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 +=
|
|
@ -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
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
/* Core pre-initialization includes. */
|
||||
#include <mesosphere/kern_select_cpu.hpp>
|
||||
#include <mesosphere/kern_select_system_control.hpp>
|
||||
#include <mesosphere/kern_k_target_system.hpp>
|
||||
|
||||
/* Initialization headers. */
|
||||
#include <mesosphere/init/kern_init_elf.hpp>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -34,43 +34,62 @@ namespace ams::kern::arch::arm64 {
|
|||
static constexpr size_t LevelBits = 9;
|
||||
static_assert(NumLevels > 0);
|
||||
|
||||
static constexpr size_t AddressBits = (NumLevels - 1) * LevelBits + PageBits;
|
||||
static_assert(AddressBits <= BITSIZEOF(u64));
|
||||
static constexpr size_t AddressSpaceSize = (1ull << AddressBits);
|
||||
template<size_t Offset, size_t Count>
|
||||
static constexpr ALWAYS_INLINE u64 GetBits(u64 value) {
|
||||
return (value >> Offset) & ((1ul << Count) - 1);
|
||||
}
|
||||
|
||||
template<size_t Offset, size_t Count>
|
||||
constexpr ALWAYS_INLINE u64 SelectBits(u64 value) {
|
||||
return value & (((1ul << Count) - 1) << Offset);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetL0Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 0), LevelBits>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetL1Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 1), LevelBits>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetL2Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 2), LevelBits>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetL3Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 3), LevelBits>(GetInteger(addr)); }
|
||||
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1)>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2)>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3)>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetContiguousL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1) + 4>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetContiguousL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2) + 4>(GetInteger(addr)); }
|
||||
static constexpr ALWAYS_INLINE uintptr_t GetContiguousL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3) + 4>(GetInteger(addr)); }
|
||||
private:
|
||||
L1PageTableEntry *table;
|
||||
bool is_kernel;
|
||||
u32 num_entries;
|
||||
public:
|
||||
ALWAYS_INLINE KVirtualAddress GetTableEntry(KVirtualAddress table, size_t index) {
|
||||
ALWAYS_INLINE KVirtualAddress GetTableEntry(KVirtualAddress table, size_t index) const {
|
||||
return table + index * sizeof(PageTableEntry);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) {
|
||||
return GetPointer<L1PageTableEntry>(GetTableEntry(KVirtualAddress(this->table), (GetInteger(address) >> (PageBits + LevelBits * 2)) & (this->num_entries - 1)));
|
||||
ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) const {
|
||||
return GetPointer<L1PageTableEntry>(GetTableEntry(KVirtualAddress(this->table), GetL1Index(address) & (this->num_entries - 1)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) {
|
||||
return GetPointer<L2PageTableEntry>(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 1)) & ((1ul << LevelBits) - 1)));
|
||||
ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) const {
|
||||
return GetPointer<L2PageTableEntry>(GetTableEntry(table, GetL2Index(address)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KProcessAddress address) {
|
||||
ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KProcessAddress address) const {
|
||||
return GetL2EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) {
|
||||
return GetPointer<L3PageTableEntry>(GetTableEntry(table, (GetInteger(address) >> (PageBits + LevelBits * 0)) & ((1ul << LevelBits) - 1)));
|
||||
ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) const {
|
||||
return GetPointer<L3PageTableEntry>(GetTableEntry(table, GetL3Index(address)));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KProcessAddress address) {
|
||||
ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KProcessAddress address) const {
|
||||
return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
|
||||
}
|
||||
public:
|
||||
constexpr KPageTableImpl() : table(), is_kernel(), num_entries() { /* ... */ }
|
||||
|
||||
NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end);
|
||||
|
||||
L1PageTableEntry *Finalize();
|
||||
|
||||
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
class KSystemControl {
|
||||
public:
|
||||
|
@ -37,14 +37,16 @@ namespace ams::kern {
|
|||
};
|
||||
public:
|
||||
/* Initialization. */
|
||||
static NOINLINE void Initialize();
|
||||
static NOINLINE void InitializePhase1();
|
||||
static NOINLINE void InitializePhase2();
|
||||
static NOINLINE u32 GetInitialProcessBinaryPool();
|
||||
|
||||
/* Randomness. */
|
||||
static void GenerateRandomBytes(void *dst, size_t size);
|
||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
||||
|
||||
/* Panic. */
|
||||
/* Power management. */
|
||||
static void SleepSystem();
|
||||
static NORETURN void StopSystem();
|
||||
};
|
||||
|
|
@ -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"
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
|
||||
#ifdef ATMOSPHERE_ARCH_ARM64
|
||||
#include <mesosphere/arch/arm64/kern_k_exception_context.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
using ams::kern::arch::arm64::KExceptionContext;
|
||||
}
|
||||
#else
|
||||
#error "Unknown board for KExceptionContext"
|
||||
#error "Unknown architecture for KExceptionContext"
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_select_system_control.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KSystemControl;
|
||||
|
||||
class KTargetSystem {
|
||||
private:
|
||||
friend class KSystemControl;
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
|
||||
#ifdef ATMOSPHERE_ARCH_ARM64
|
||||
#include <mesosphere/arch/arm64/kern_k_thread_context.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
using ams::kern::arch::arm64::KThreadContext;
|
||||
}
|
||||
#else
|
||||
#error "Unknown board for KThreadContext"
|
||||
#error "Unknown architecture for KThreadContext"
|
||||
#endif
|
||||
|
|
|
@ -15,10 +15,14 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_target_system.hpp>
|
||||
|
||||
#ifdef ATMOSPHERE_BOARD_NINTENDO_SWITCH
|
||||
#include <mesosphere/board/nintendo/switch/kern_k_system_control.hpp>
|
||||
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
|
||||
#include <mesosphere/board/nintendo/nx/kern_k_system_control.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
using ams::kern::board::nintendo::nx::KSystemControl;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Unknown board for KSystemControl"
|
||||
#endif
|
||||
|
|
|
@ -20,11 +20,55 @@ namespace ams::kern::arch::arm64 {
|
|||
void KPageTableImpl::InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end) {
|
||||
this->table = static_cast<L1PageTableEntry *>(tb);
|
||||
this->is_kernel = true;
|
||||
this->num_entries = util::AlignUp(end - start, AddressSpaceSize) / AddressSpaceSize;
|
||||
this->num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize;
|
||||
}
|
||||
|
||||
L1PageTableEntry *KPageTableImpl::Finalize() {
|
||||
return this->table;
|
||||
}
|
||||
|
||||
bool KPageTableImpl::GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
|
||||
/* Validate that we can read the actual entry. */
|
||||
const size_t l0_index = GetL0Index(address);
|
||||
const size_t l1_index = GetL1Index(address);
|
||||
if (this->is_kernel) {
|
||||
/* Kernel entries must be accessed via TTBR1. */
|
||||
if ((l0_index != MaxPageTableEntries - 1) || (l1_index < MaxPageTableEntries - this->num_entries)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* User entries must be accessed with TTBR0. */
|
||||
if ((l0_index != 0) || l1_index >= this->num_entries) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to get from l1 table. */
|
||||
const L1PageTableEntry *l1_entry = this->GetL1Entry(address);
|
||||
if (l1_entry->IsBlock()) {
|
||||
*out = l1_entry->GetBlock() + GetL1Offset(address);
|
||||
return true;
|
||||
} else if (!l1_entry->IsTable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Try to get from l2 table. */
|
||||
const L2PageTableEntry *l2_entry = this->GetL2Entry(l1_entry, address);
|
||||
if (l2_entry->IsBlock()) {
|
||||
*out = l2_entry->GetBlock() + GetL2Offset(address);
|
||||
return true;
|
||||
} else if (!l2_entry->IsTable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Try to get from l3 table. */
|
||||
const L3PageTableEntry *l3_entry = this->GetL3Entry(l2_entry, address);
|
||||
if (l3_entry->IsBlock()) {
|
||||
*out = l3_entry->GetBlock() + GetL3Offset(address);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
}
|
|
@ -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
|
|
@ -15,14 +15,20 @@
|
|||
*/
|
||||
#include <mesosphere.hpp>
|
||||
#include "kern_secure_monitor.hpp"
|
||||
#include "kern_k_sleep_manager.hpp"
|
||||
|
||||
namespace ams::kern {
|
||||
namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Global variables for panic. */
|
||||
bool g_call_smc_on_panic;
|
||||
|
||||
/* Global variables for secure memory. */
|
||||
constexpr size_t SecureAppletReservedMemorySize = 4_MB;
|
||||
KVirtualAddress g_secure_applet_memory_address;
|
||||
|
||||
|
||||
/* Global variables for randomness. */
|
||||
/* Nintendo uses std::mt19937_t for randomness. */
|
||||
/* To save space (and because mt19337_t isn't secure anyway), */
|
||||
|
@ -195,7 +201,7 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* System Initialization. */
|
||||
void KSystemControl::Initialize() {
|
||||
void KSystemControl::InitializePhase1() {
|
||||
/* Set IsDebugMode. */
|
||||
{
|
||||
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
||||
|
@ -250,6 +256,21 @@ namespace ams::kern {
|
|||
}
|
||||
}
|
||||
|
||||
void KSystemControl::InitializePhase2() {
|
||||
/* Initialize the sleep manager. */
|
||||
KSleepManager::Initialize();
|
||||
|
||||
/* Reserve secure applet memory. */
|
||||
{
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null<KVirtualAddress>);
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletReservedMemorySize));
|
||||
|
||||
constexpr auto SecureAppletAllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
g_secure_applet_memory_address = Kernel::GetMemoryManager().AllocateContinuous(SecureAppletReservedMemorySize / PageSize, 1, SecureAppletAllocateOption);
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>);
|
||||
}
|
||||
}
|
||||
|
||||
u32 KSystemControl::GetInitialProcessBinaryPool() {
|
||||
return KMemoryManager::Pool_Application;
|
||||
}
|
||||
|
@ -274,6 +295,11 @@ namespace ams::kern {
|
|||
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
|
||||
}
|
||||
|
||||
void KSystemControl::SleepSystem() {
|
||||
MESOSPHERE_LOG("SleepSystem() was called\n");
|
||||
KSleepManager::SleepSystem();
|
||||
}
|
||||
|
||||
void KSystemControl::StopSystem() {
|
||||
if (g_call_smc_on_panic) {
|
||||
/* Display a panic screen via secure monitor. */
|
|
@ -16,7 +16,7 @@
|
|||
#include <mesosphere.hpp>
|
||||
#include "kern_secure_monitor.hpp"
|
||||
|
||||
namespace ams::kern::smc {
|
||||
namespace ams::kern::board::nintendo::nx::smc {
|
||||
|
||||
namespace {
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
#pragma once
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern::smc {
|
||||
namespace ams::kern::board::nintendo::nx::smc {
|
||||
|
||||
/* Types. */
|
||||
enum MemorySize {
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
#include "../../../kern_debug_log_impl.hpp"
|
||||
#include "kern_debug_log_impl.hpp"
|
||||
|
||||
namespace ams::kern {
|
||||
|
|
@ -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();");
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#pragma once
|
||||
#include <vapours/svc/svc_types_common.hpp>
|
||||
|
||||
namespace ams::svc::board::nintendo_switch {
|
||||
namespace ams::svc::board::nintendo::nx {
|
||||
|
||||
enum DeviceName {
|
||||
DeviceName_Afi = 0,
|
|
@ -16,7 +16,7 @@
|
|||
#pragma once
|
||||
#include <vapours/svc/svc_types_common.hpp>
|
||||
|
||||
namespace ams::svc::board::nintendo_switch {
|
||||
namespace ams::svc::board::nintendo::nx {
|
||||
|
||||
constexpr inline const s64 TicksPerSecond = 19'200'000;
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue