kern/loader: make aware of new address space and shadow stack region

This commit is contained in:
Alula committed 2026-09-15 17:04:50 +02:00
1 parent e6a3d71692
commit 0f15010ba5
25 files changed
+238 -99

No files matched your search

@@ -81,6 +81,7 @@ namespace ams::kern::arch::arm64::cpu {
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpEl0, sp_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpEl0, sp_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(IdAa64Dfr0El1, id_aa64dfr0_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(IdAa64Dfr0El1, id_aa64dfr0_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(IdAa64Mmfr0El1, id_aa64mmfr0_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcrEl0, pmcr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcrEl0, pmcr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmUserEnrEl0, pmuserenr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmUserEnrEl0, pmuserenr_el0)
@@ -94,10 +94,10 @@ namespace ams::kern::arch::arm64 {
return KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(KPageTable::GetBlockType(alignment) + 1)); return KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(KPageTable::GetBlockType(alignment) + 1));
} }
public: public:
/* TODO: How should this size be determined. Does the KProcess slab count need to go in a header as a define? */ static constexpr size_t NumPTEntries = ::ams::kern::init::SlabCountKProcess + 1; /* +1 for kernel. */
static constexpr size_t NumTtbr0Entries = 81;
private: private:
static constinit inline const volatile u64 s_ttbr0_entries[NumTtbr0Entries] = {}; static constinit inline const volatile u64 s_ttbr0_entries[NumPTEntries] = {};
static constinit inline const volatile u64 s_tcr_el1_entries[NumPTEntries] = {};
private: private:
KPageTableManager *m_manager; KPageTableManager *m_manager;
u8 m_asid; u8 m_asid;
@@ -188,6 +188,12 @@ namespace ams::kern::arch::arm64 {
return s_ttbr0_entries[0]; return s_ttbr0_entries[0];
} }
static const volatile u64 &GetTcrEL1Entry(size_t index) { return s_tcr_el1_entries[index]; }
static ALWAYS_INLINE u64 GetKernelTcrEL1() {
return s_tcr_el1_entries[0];
}
static ALWAYS_INLINE void ActivateKernel() { static ALWAYS_INLINE void ActivateKernel() {
/* Activate, using asid 0 and process id = 0xFFFFFFFF */ /* Activate, using asid 0 and process id = 0xFFFFFFFF */
cpu::SwitchProcess(GetKernelTtbr0(), 0xFFFFFFFF); cpu::SwitchProcess(GetKernelTtbr0(), 0xFFFFFFFF);
@@ -302,19 +302,21 @@ namespace ams::kern::arch::arm64 {
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); } bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); }
bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); } bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); }
KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); } KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); }
KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); } KProcessAddress GetShadowStackRegionStart() const { return m_page_table.GetShadowStackRegionStart(); }
KProcessAddress GetAliasRegionStart() const { return m_page_table.GetAliasRegionStart(); } KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); }
KProcessAddress GetStackRegionStart() const { return m_page_table.GetStackRegionStart(); } KProcessAddress GetAliasRegionStart() const { return m_page_table.GetAliasRegionStart(); }
KProcessAddress GetKernelMapRegionStart() const { return m_page_table.GetKernelMapRegionStart(); } KProcessAddress GetStackRegionStart() const { return m_page_table.GetStackRegionStart(); }
KProcessAddress GetAliasCodeRegionStart() const { return m_page_table.GetAliasCodeRegionStart(); } KProcessAddress GetKernelMapRegionStart() const { return m_page_table.GetKernelMapRegionStart(); }
KProcessAddress GetAliasCodeRegionStart() const { return m_page_table.GetAliasCodeRegionStart(); }
size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); } size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); }
size_t GetHeapRegionSize() const { return m_page_table.GetHeapRegionSize(); } size_t GetShadowStackRegionSize() const { return m_page_table.GetShadowStackRegionSize(); }
size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); } size_t GetHeapRegionSize() const { return m_page_table.GetHeapRegionSize(); }
size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); } size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); }
size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); } size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); }
size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); } size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); }
size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); }
size_t GetAliasRegionExtraSize() const { return m_page_table.GetAliasRegionExtraSize(); } size_t GetAliasRegionExtraSize() const { return m_page_table.GetAliasRegionExtraSize(); }
@@ -18,6 +18,25 @@
#include <mesosphere/kern_k_slab_heap.hpp> #include <mesosphere/kern_k_slab_heap.hpp>
namespace ams::kern::init { namespace ams::kern::init {
/* Constexpr counts. */
constexpr size_t SlabCountKProcess = 80;
constexpr size_t SlabCountKThread = 800;
constexpr size_t SlabCountKEvent = 900;
constexpr size_t SlabCountKInterruptEvent = 100;
constexpr size_t SlabCountKPort = 384;
constexpr size_t SlabCountKSharedMemory = 80;
constexpr size_t SlabCountKTransferMemory = 200;
constexpr size_t SlabCountKCodeMemory = 10;
constexpr size_t SlabCountKDeviceAddressSpace = 300;
constexpr size_t SlabCountKSession = 1133;
constexpr size_t SlabCountKLightSession = 100;
constexpr size_t SlabCountKObjectName = 7;
constexpr size_t SlabCountKResourceLimit = 5;
constexpr size_t SlabCountKDebug = cpu::NumCores;
constexpr size_t SlabCountKIoPool = 1;
constexpr size_t SlabCountKIoRegion = 6;
constexpr size_t SlabcountKSessionRequestMappings = 40;
struct KSlabResourceCounts { struct KSlabResourceCounts {
size_t num_KProcess; size_t num_KProcess;
@@ -24,7 +24,7 @@ namespace ams::kern {
enum Type { enum Type {
Type_MapSmall = 0, Type_MapSmall = 0,
Type_MapLarge = 1, Type_MapLarge = 1,
Type_Map39Bit = 2, Type_MapHuge = 2,
Type_Heap = 3, Type_Heap = 3,
Type_Stack = 4, Type_Stack = 4,
Type_Alias = 5, Type_Alias = 5,
@@ -211,15 +211,15 @@ namespace ams::kern {
uintptr_t m_address; uintptr_t m_address;
size_t m_size; size_t m_size;
KMemoryState m_state; KMemoryState m_state;
u16 m_device_disable_merge_left_count;
u16 m_device_disable_merge_right_count;
u16 m_ipc_lock_count;
u16 m_device_use_count;
u16 m_ipc_disable_merge_count;
KMemoryPermission m_permission; KMemoryPermission m_permission;
KMemoryAttribute m_attribute; KMemoryAttribute m_attribute;
KMemoryPermission m_original_permission; KMemoryPermission m_original_permission;
u16 m_ipc_lock_count;
u16 m_device_use_count;
KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; KMemoryBlockDisableMergeAttribute m_disable_merge_attribute;
u16 m_ipc_disable_merge_count;
u16 m_device_disable_merge_left_count;
u16 m_device_disable_merge_right_count;
constexpr ams::svc::MemoryInfo GetSvcMemoryInfo() const { constexpr ams::svc::MemoryInfo GetSvcMemoryInfo() const {
return { return {
@@ -365,15 +365,15 @@ namespace ams::kern {
.m_address = GetInteger(this->GetAddress()), .m_address = GetInteger(this->GetAddress()),
.m_size = this->GetSize(), .m_size = this->GetSize(),
.m_state = m_memory_state, .m_state = m_memory_state,
.m_device_disable_merge_left_count = m_device_disable_merge_left_count,
.m_device_disable_merge_right_count = m_device_disable_merge_right_count,
.m_ipc_lock_count = m_ipc_lock_count,
.m_device_use_count = m_device_use_count,
.m_ipc_disable_merge_count = m_ipc_disable_merge_count,
.m_permission = m_permission, .m_permission = m_permission,
.m_attribute = m_attribute, .m_attribute = m_attribute,
.m_original_permission = m_original_permission, .m_original_permission = m_original_permission,
.m_ipc_lock_count = m_ipc_lock_count,
.m_device_use_count = m_device_use_count,
.m_disable_merge_attribute = m_disable_merge_attribute, .m_disable_merge_attribute = m_disable_merge_attribute,
.m_ipc_disable_merge_count = m_ipc_disable_merge_count,
.m_device_disable_merge_left_count = m_device_disable_merge_left_count,
.m_device_disable_merge_right_count = m_device_disable_merge_right_count,
}; };
} }
public: public:
@@ -90,10 +90,11 @@ namespace ams::kern {
}; };
enum RegionType { enum RegionType {
RegionType_KernelMap = 0, RegionType_KernelMap = 0,
RegionType_Stack = 1, RegionType_Stack = 1,
RegionType_Alias = 2, RegionType_Alias = 2,
RegionType_Heap = 3, RegionType_Heap = 3,
RegionType_ShadowStack = 4,
RegionType_Count, RegionType_Count,
}; };
@@ -196,7 +197,6 @@ namespace ams::kern {
KPageTableImpl m_impl; KPageTableImpl m_impl;
KMemoryBlockManager m_memory_block_manager; KMemoryBlockManager m_memory_block_manager;
u32 m_allocate_option; u32 m_allocate_option;
u32 m_address_space_width;
bool m_is_kernel; bool m_is_kernel;
bool m_enable_aslr; bool m_enable_aslr;
bool m_enable_device_address_space_merge; bool m_enable_device_address_space_merge;
@@ -212,23 +212,24 @@ namespace ams::kern {
public: public:
constexpr explicit KPageTableBase(util::ConstantInitializeTag) constexpr explicit KPageTableBase(util::ConstantInitializeTag)
: m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>), : m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>),
m_region_starts{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>}, m_region_starts{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>},
m_region_ends{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>}, m_region_ends{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>},
m_current_heap_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>), m_current_heap_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>),
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>), m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(), m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(),
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize), m_mapped_ipc_server_memory(), m_alias_region_extra_size(), m_general_lock(), m_map_physical_memory_lock(),
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allowed_exec_device_mapping(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(), m_allocate_option(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allowed_exec_device_mapping(),
m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value() m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(),
m_cached_physical_heap_region(), m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value()
{ {
/* ... */ /* ... */
} }
explicit KPageTableBase() { /* ... */ } explicit KPageTableBase() { /* ... */ }
NOINLINE void InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end); NOINLINE void InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit); NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, void *table, KProcessAddress start, KProcessAddress end, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
void Finalize(); void Finalize();
@@ -247,6 +248,14 @@ namespace ams::kern {
return this->Contains(addr, size) && m_region_starts[RegionType_Alias] <= addr && addr + size - 1 <= m_region_ends[RegionType_Alias] - 1; return this->Contains(addr, size) && m_region_starts[RegionType_Alias] <= addr && addr + size - 1 <= m_region_ends[RegionType_Alias] - 1;
} }
constexpr bool IsInShadowStackRegion(KProcessAddress addr, size_t size) const {
return this->Contains(addr, size) && m_region_starts[RegionType_ShadowStack] <= addr && addr + size - 1 <= m_region_ends[RegionType_ShadowStack] - 1;
}
constexpr bool IsSafeUserPointer(KProcessAddress addr, size_t size) const {
return this->Contains(addr, size) && !this->IsInShadowStackRegion(addr, size);
}
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
/* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */ /* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */
return this->CanContain(addr, size, ams::svc::MemoryState_AliasCode); return this->CanContain(addr, size, ams::svc::MemoryState_AliasCode);
@@ -490,19 +499,21 @@ namespace ams::kern {
public: public:
KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; } KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; }
KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; } KProcessAddress GetShadowStackRegionStart() const { return m_region_starts[RegionType_ShadowStack]; }
KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; } KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; }
KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; } KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; }
KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; } KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; }
KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; }
KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; } KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; }
size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; } size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; }
size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; } size_t GetShadowStackRegionSize() const { return m_region_ends[RegionType_ShadowStack] - m_region_starts[RegionType_ShadowStack]; }
size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; } size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; }
size_t GetStackRegionSize() const { return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; } size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; }
size_t GetKernelMapRegionSize() const { return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; } size_t GetStackRegionSize() const { return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; }
size_t GetKernelMapRegionSize() const { return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; }
size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; } size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; }
@@ -215,6 +215,7 @@ namespace ams::kern {
} }
u32 GetAllocateOption() const { return m_page_table.GetAllocateOption(); } u32 GetAllocateOption() const { return m_page_table.GetAllocateOption(); }
size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); }
ThreadList &GetThreadList() { return m_thread_list; } ThreadList &GetThreadList() { return m_thread_list; }
const ThreadList &GetThreadList() const { return m_thread_list; } const ThreadList &GetThreadList() const { return m_thread_list; }
@@ -125,7 +125,7 @@ namespace ams::kern::arch::arm64 {
m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer(); m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer();
/* Initialize the base page table. */ /* Initialize the base page table. */
KPageTableBase::InitializeForKernel(true, table, start, end); KPageTableBase::InitializeForKernel(table, start, end);
} }
Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) { Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) {
@@ -144,7 +144,7 @@ namespace ams::kern::arch::arm64 {
const size_t as_width = GetAddressSpaceWidth(flags); const size_t as_width = GetAddressSpaceWidth(flags);
const KProcessAddress as_start = 0; const KProcessAddress as_start = 0;
const KProcessAddress as_end = (1ul << as_width); const KProcessAddress as_end = (1ul << as_width);
R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(ttbr0_virt), as_start, as_end, code_address, code_size, system_resource, resource_limit)); R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, GetVoidPointer(ttbr0_virt), as_start, as_end, pool, code_address, code_size, system_resource, resource_limit));
/* Note that we've updated the table (since we created it). */ /* Note that we've updated the table (since we created it). */
this->NoteUpdated(); this->NoteUpdated();
@@ -60,25 +60,6 @@ namespace ams::kern::init {
#undef DEFINE_SLAB_TYPE_ENUM_MEMBER #undef DEFINE_SLAB_TYPE_ENUM_MEMBER
/* Constexpr counts. */
constexpr size_t SlabCountKProcess = 80;
constexpr size_t SlabCountKThread = 800;
constexpr size_t SlabCountKEvent = 900;
constexpr size_t SlabCountKInterruptEvent = 100;
constexpr size_t SlabCountKPort = 384;
constexpr size_t SlabCountKSharedMemory = 80;
constexpr size_t SlabCountKTransferMemory = 200;
constexpr size_t SlabCountKCodeMemory = 10;
constexpr size_t SlabCountKDeviceAddressSpace = 300;
constexpr size_t SlabCountKSession = 1133;
constexpr size_t SlabCountKLightSession = 100;
constexpr size_t SlabCountKObjectName = 7;
constexpr size_t SlabCountKResourceLimit = 5;
constexpr size_t SlabCountKDebug = cpu::NumCores;
constexpr size_t SlabCountKIoPool = 1;
constexpr size_t SlabCountKIoRegion = 6;
constexpr size_t SlabcountKSessionRequestMappings = 40;
constexpr size_t SlabCountExtraKThread = (1024 + 256 + 256) - SlabCountKThread; constexpr size_t SlabCountExtraKThread = (1024 + 256 + 256) - SlabCountKThread;
namespace test { namespace test {
@@ -30,15 +30,20 @@ namespace ams::kern {
{ 36, ams::svc::AddressLargeMap36Start, ams::svc::AddressLargeMap36Size, KAddressSpaceInfo::Type_MapLarge, }, { 36, ams::svc::AddressLargeMap36Start, ams::svc::AddressLargeMap36Size, KAddressSpaceInfo::Type_MapLarge, },
{ 36, Invalid, ams::svc::AddressMemoryRegionHeap36Size, KAddressSpaceInfo::Type_Heap, }, { 36, Invalid, ams::svc::AddressMemoryRegionHeap36Size, KAddressSpaceInfo::Type_Heap, },
{ 36, Invalid, ams::svc::AddressMemoryRegionAlias36Size, KAddressSpaceInfo::Type_Alias, }, { 36, Invalid, ams::svc::AddressMemoryRegionAlias36Size, KAddressSpaceInfo::Type_Alias, },
{ 39, ams::svc::AddressMap39Start, ams::svc::AddressMap39Size, KAddressSpaceInfo::Type_Map39Bit, }, { 39, ams::svc::AddressMap39Start, ams::svc::AddressMap39Size, KAddressSpaceInfo::Type_MapHuge, },
{ 39, Invalid, ams::svc::AddressMemoryRegionSmall39Size, KAddressSpaceInfo::Type_MapSmall, }, { 39, Invalid, ams::svc::AddressMemoryRegionSmall39Size, KAddressSpaceInfo::Type_MapSmall, },
{ 39, Invalid, ams::svc::AddressMemoryRegionHeap39Size, KAddressSpaceInfo::Type_Heap, }, { 39, Invalid, ams::svc::AddressMemoryRegionHeap39Size, KAddressSpaceInfo::Type_Heap, },
{ 39, Invalid, ams::svc::AddressMemoryRegionAlias39Size, KAddressSpaceInfo::Type_Alias, }, { 39, Invalid, ams::svc::AddressMemoryRegionAlias39Size, KAddressSpaceInfo::Type_Alias, },
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, }, { 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
{ 42, ams::svc::AddressMap42Start, ams::svc::AddressMap42Size, KAddressSpaceInfo::Type_MapHuge, },
{ 42, Invalid, ams::svc::AddressMemoryRegionSmall42Size, KAddressSpaceInfo::Type_MapSmall, },
{ 42, Invalid, 0, KAddressSpaceInfo::Type_Heap, },
{ 42, Invalid, ams::svc::AddressMemoryRegionAlias42Size, KAddressSpaceInfo::Type_Alias, },
{ 42, Invalid, ams::svc::AddressMemoryRegionStack42Size, KAddressSpaceInfo::Type_Stack, },
}; };
constexpr u8 FlagsToAddressSpaceWidthTable[4] = { constexpr u8 FlagsToAddressSpaceWidthTable[5] = {
32, 36, 32, 39 32, 36, 32, 39, 42
}; };
constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag flags) { constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag flags) {
@@ -54,6 +59,7 @@ namespace ams::kern {
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated) == 36); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated) == 36);
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) == 32); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) == 32);
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit) == 39); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit) == 39);
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage) == 42);
KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) { KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
for (auto &info : AddressSpaceInfos) { for (auto &info : AddressSpaceInfos) {
@@ -233,7 +233,7 @@ namespace ams::kern {
/* a number of pages here. Even though this is presumably only used for debug assertions, this is */ /* a number of pages here. Even though this is presumably only used for debug assertions, this is */
/* almost certainly a bug. */ /* almost certainly a bug. */
using ASType = KAddressSpaceInfo::Type; using ASType = KAddressSpaceInfo::Type;
const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall; const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_MapHuge : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall;
const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type, out->code_num_pages); const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type, out->code_num_pages);
const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type); const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type);
const uintptr_t map_end = map_start + map_size; const uintptr_t map_end = map_start + map_size;
@@ -88,14 +88,14 @@ namespace ams::kern {
} }
} }
void KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) { void KPageTableBase::InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end) {
/* Initialize our members. */ /* Initialize our members. */
m_address_space_width = (is_64_bit) ? BITSIZEOF(u64) : BITSIZEOF(u32);
m_address_space_start = KProcessAddress(GetInteger(start)); m_address_space_start = KProcessAddress(GetInteger(start));
m_address_space_end = KProcessAddress(GetInteger(end)); m_address_space_end = KProcessAddress(GetInteger(end));
m_is_kernel = true; m_is_kernel = true;
m_enable_aslr = true; m_enable_aslr = true;
m_enable_device_address_space_merge = false; m_enable_device_address_space_merge = false;
m_allowed_exec_device_mapping = false;
for (auto i = 0; i < RegionType_Count; ++i) { for (auto i = 0; i < RegionType_Count; ++i) {
m_region_starts[i] = 0; m_region_starts[i] = 0;
@@ -133,7 +133,7 @@ namespace ams::kern {
MESOSPHERE_R_ABORT_UNLESS(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager)); MESOSPHERE_R_ABORT_UNLESS(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
} }
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, void *table, KProcessAddress start, KProcessAddress end, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
/* Validate the region. */ /* Validate the region. */
MESOSPHERE_ABORT_UNLESS(start <= code_address); MESOSPHERE_ABORT_UNLESS(start <= code_address);
MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size); MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size);
@@ -151,9 +151,9 @@ namespace ams::kern {
m_alias_region_extra_size = 0; m_alias_region_extra_size = 0;
/* Set our width and heap/alias sizes. */ /* Set our width and heap/alias sizes. */
m_address_space_width = GetAddressSpaceWidth(flags); size_t address_space_width = GetAddressSpaceWidth(flags);
size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias); size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias);
size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap); size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap);
/* Set code regions and determine remaining sizes. */ /* Set code regions and determine remaining sizes. */
KProcessAddress process_code_start; KProcessAddress process_code_start;
@@ -162,12 +162,12 @@ namespace ams::kern {
size_t kernel_map_region_size; size_t kernel_map_region_size;
KProcessAddress before_process_code_start, after_process_code_start; KProcessAddress before_process_code_start, after_process_code_start;
size_t before_process_code_size, after_process_code_size; size_t before_process_code_size, after_process_code_size;
if (m_address_space_width == 39) { if (address_space_width == 39 || address_space_width == 42) {
stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Stack); stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Stack);
kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall); kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall);
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Map39Bit); m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_MapHuge);
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Map39Bit); m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_MapHuge);
m_alias_code_region_start = m_code_region_start; m_alias_code_region_start = m_code_region_start;
m_alias_code_region_end = m_code_region_end; m_alias_code_region_end = m_code_region_end;
@@ -182,7 +182,7 @@ namespace ams::kern {
/* If we have a 39-bit address space and should, enable extra size to the alias region. */ /* If we have a 39-bit address space and should, enable extra size to the alias region. */
if (flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) { if (flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) {
/* Extra size is 1/8th of the address space. */ /* Extra size is 1/8th of the address space. */
m_alias_region_extra_size = (static_cast<size_t>(1) << m_address_space_width) / 8; m_alias_region_extra_size = (static_cast<size_t>(1) << address_space_width) / 8;
alias_region_size += m_alias_region_extra_size; alias_region_size += m_alias_region_extra_size;
} }
@@ -208,6 +208,9 @@ namespace ams::kern {
after_process_code_size = GetSpaceSize(KAddressSpaceInfo::Type_MapLarge); after_process_code_size = GetSpaceSize(KAddressSpaceInfo::Type_MapLarge);
} }
m_region_starts[RegionType_ShadowStack] = Null<KProcessAddress>;
m_region_ends[RegionType_ShadowStack] = Null<KProcessAddress>;
/* Set other basic fields. */ /* Set other basic fields. */
m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0; m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0; m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
@@ -237,6 +240,9 @@ namespace ams::kern {
region_layouts[num_regions++] = { .size = alias_region_size, .type = RegionType_Alias, .alloc_index = 0, }; region_layouts[num_regions++] = { .size = alias_region_size, .type = RegionType_Alias, .alloc_index = 0, };
region_layouts[num_regions++] = { .size = heap_region_size, .type = RegionType_Heap, .alloc_index = 0, }; region_layouts[num_regions++] = { .size = heap_region_size, .type = RegionType_Heap, .alloc_index = 0, };
if (flags & ams::svc::CreateProcessFlag_EnableShadowStack) {
region_layouts[num_regions++] = { .size = ams::svc::AddressShadowStackRegionSize, .type = RegionType_ShadowStack, .alloc_index = 0, };
}
/* Selection-sort the regions by size largest-to-smallest. */ /* Selection-sort the regions by size largest-to-smallest. */
for (size_t i = 0; i < num_regions - 1; ++i) { for (size_t i = 0; i < num_regions - 1; ++i) {
@@ -399,6 +405,18 @@ namespace ams::kern {
break; break;
} }
} }
/* Check for overlap with shadow stack. */
for (size_t ss = 0; ss < num_regions; ++ss) {
if (const auto &shadow_stack_region = region_layouts[ss]; shadow_stack_region.type == RegionType_ShadowStack) {
if (shadow_stack_region.size != 0) {
const KProcessAddress shadow_stack_start = m_region_starts[RegionType_ShadowStack];
const KProcessAddress shadow_stack_last = m_region_ends[RegionType_ShadowStack] - 1;
MESOSPHERE_ABORT_UNLESS(kmap_last < shadow_stack_start || shadow_stack_last < kmap_start);
}
break;
}
}
} }
} }
@@ -494,6 +512,25 @@ namespace ams::kern {
MESOSPHERE_ABORT_UNLESS(heap_last < process_code_start || process_code_last < heap_start); MESOSPHERE_ABORT_UNLESS(heap_last < process_code_start || process_code_last < heap_start);
} }
} }
/* Check that the ShadowStack region is valid. */
for (size_t ss = 0; ss < num_regions; ++ss) {
if (const auto &shadow_stack_region = region_layouts[ss]; shadow_stack_region.type == RegionType_ShadowStack) {
/* If there's no shadow stack region, we have nothing to check. */
if (shadow_stack_region.size == 0) {
break;
}
/* Check that the shadow stack region is within our address space. */
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_ShadowStack]));
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_ShadowStack]));
/* Check for overlap with process code. */
const KProcessAddress shadow_stack_start = m_region_starts[RegionType_ShadowStack];
const KProcessAddress shadow_stack_last = m_region_ends[RegionType_ShadowStack] - 1;
MESOSPHERE_ABORT_UNLESS(shadow_stack_last < process_code_start || process_code_last < shadow_stack_start);
}
}
} }
/* Set heap and fill members. */ /* Set heap and fill members. */
@@ -1997,15 +2034,15 @@ namespace ams::kern {
.m_address = GetInteger(m_address_space_end), .m_address = GetInteger(m_address_space_end),
.m_size = 0 - GetInteger(m_address_space_end), .m_size = 0 - GetInteger(m_address_space_end),
.m_state = static_cast<KMemoryState>(ams::svc::MemoryState_Inaccessible), .m_state = static_cast<KMemoryState>(ams::svc::MemoryState_Inaccessible),
.m_device_disable_merge_left_count = 0,
.m_device_disable_merge_right_count = 0,
.m_ipc_lock_count = 0,
.m_device_use_count = 0,
.m_ipc_disable_merge_count = 0,
.m_permission = KMemoryPermission_None, .m_permission = KMemoryPermission_None,
.m_attribute = KMemoryAttribute_None, .m_attribute = KMemoryAttribute_None,
.m_original_permission = KMemoryPermission_None, .m_original_permission = KMemoryPermission_None,
.m_ipc_lock_count = 0,
.m_device_use_count = 0,
.m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute_None, .m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute_None,
.m_ipc_disable_merge_count = 0,
.m_device_disable_merge_left_count = 0,
.m_device_disable_merge_right_count = 0,
}; };
out_page_info->flags = 0; out_page_info->flags = 0;
@@ -109,6 +109,15 @@ namespace ams::kern::svc {
case ams::svc::InfoType_AliasRegionExtraSize: case ams::svc::InfoType_AliasRegionExtraSize:
*out = process->GetPageTable().GetAliasRegionExtraSize(); *out = process->GetPageTable().GetAliasRegionExtraSize();
break; break;
case ams::svc::InfoType_AddressSpaceSize:
*out = process->GetAddressSpaceSize();
break;
case ams::svc::InfoType_ShadowStackRegionAddress:
*out = GetInteger(process->GetPageTable().GetShadowStackRegionStart());
break;
case ams::svc::InfoType_ShadowStackRegionSize:
*out = process->GetPageTable().GetShadowStackRegionSize();
break;
MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
} }
@@ -138,6 +147,9 @@ namespace ams::kern::svc {
case ams::svc::InfoType_IsApplication: case ams::svc::InfoType_IsApplication:
case ams::svc::InfoType_FreeThreadCount: case ams::svc::InfoType_FreeThreadCount:
case ams::svc::InfoType_AliasRegionExtraSize: case ams::svc::InfoType_AliasRegionExtraSize:
case ams::svc::InfoType_AddressSpaceSize:
case ams::svc::InfoType_ShadowStackRegionAddress:
case ams::svc::InfoType_ShadowStackRegionSize:
{ {
/* These info types don't support non-zero subtypes. */ /* These info types don't support non-zero subtypes. */
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
@@ -100,6 +100,9 @@ namespace ams::kern::svc {
/* Validate that the parameter flags are valid. */ /* Validate that the parameter flags are valid. */
R_UNLESS((params.flags & ~ams::svc::CreateProcessFlag_All) == 0, svc::ResultInvalidEnumValue()); R_UNLESS((params.flags & ~ams::svc::CreateProcessFlag_All) == 0, svc::ResultInvalidEnumValue());
/* The 64KB page size is not yet allowed. */
R_UNLESS((params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask) != ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage, svc::ResultInvalidCombination());
/* Validate that 64-bit process is okay. */ /* Validate that 64-bit process is okay. */
const bool is_64_bit = (params.flags & ams::svc::CreateProcessFlag_Is64Bit) != 0; const bool is_64_bit = (params.flags & ams::svc::CreateProcessFlag_Is64Bit) != 0;
if constexpr (sizeof(void *) < sizeof(u64)) { if constexpr (sizeof(void *) < sizeof(u64)) {
@@ -130,12 +133,13 @@ namespace ams::kern::svc {
} }
break; break;
case ams::svc::CreateProcessFlag_AddressSpace64Bit: case ams::svc::CreateProcessFlag_AddressSpace64Bit:
case ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage:
{ {
/* 64-bit address space requires 64-bit process. */ /* 64-bit address space requires 64-bit process. */
R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); R_UNLESS(is_64_bit, svc::ResultInvalidCombination());
map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit, code_size); map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapHuge, code_size);
map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit); map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapHuge);
map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Heap); map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Heap);
} }
@@ -35,6 +35,7 @@ namespace ams::cfg {
OverrideStatusFlag_AddressSpace64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift,
OverrideStatusFlag_AddressSpace32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift,
OverrideStatusFlag_AddressSpace64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift,
OverrideStatusFlag_AddressSpace64Bit64KPage = (svc::CreateProcessFlag_AddressSpace64Bit64KPage >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift,
#endif #endif
}; };
@@ -235,11 +235,16 @@ namespace ams::ldr {
MetaFlag_PreventCodeReads = (1 << 7), MetaFlag_PreventCodeReads = (1 << 7),
}; };
enum MetaFlag2 {
MetaFlag2_EnableShadowStack = (1 << 0),
};
enum AddressSpaceType { enum AddressSpaceType {
AddressSpaceType_32Bit = 0, AddressSpaceType_32Bit = 0,
AddressSpaceType_64BitDeprecated = 1, AddressSpaceType_64BitDeprecated = 1,
AddressSpaceType_32BitWithoutAlias = 2, AddressSpaceType_32BitWithoutAlias = 2,
AddressSpaceType_64Bit = 3, AddressSpaceType_64Bit = 3,
AddressSpaceType_64Bit64KPage = 4,
}; };
#if defined(ATMOSPHERE_OS_HORIZON) #if defined(ATMOSPHERE_OS_HORIZON)
@@ -247,13 +252,14 @@ namespace ams::ldr {
static_assert(AddressSpaceType_64BitDeprecated == (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_64BitDeprecated == (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift));
static_assert(AddressSpaceType_32BitWithoutAlias == (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_32BitWithoutAlias == (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift));
static_assert(AddressSpaceType_64Bit == (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_64Bit == (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift));
static_assert(AddressSpaceType_64Bit64KPage == (svc::CreateProcessFlag_AddressSpace64Bit64KPage >> svc::CreateProcessFlag_AddressSpaceShift));
#endif #endif
u32 magic; u32 magic;
u32 signature_key_generation; u32 signature_key_generation;
u8 reserved_08[4]; u8 reserved_08[4];
u8 flags; u8 flags;
u8 reserved_0D; u8 flags2;
u8 main_thread_priority; u8 main_thread_priority;
u8 default_cpu_id; u8 default_cpu_id;
u8 reserved_10[4]; u8 reserved_10[4];
@@ -153,6 +153,8 @@ namespace ams::cfg {
impl::OverrideStatusFlag ParseOverrideAddressSpace(const char *value) { impl::OverrideStatusFlag ParseOverrideAddressSpace(const char *value) {
if (strcasecmp(value, "39_bit") == 0 || strcasecmp(value, "39") == 0) { if (strcasecmp(value, "39_bit") == 0 || strcasecmp(value, "39") == 0) {
return impl::OverrideStatusFlag_AddressSpace64Bit; return impl::OverrideStatusFlag_AddressSpace64Bit;
} else if (strcasecmp(value, "42_bit") == 0 || strcasecmp(value, "42") == 0) {
return impl::OverrideStatusFlag_AddressSpace64Bit64KPage;
} else if (strcasecmp(value, "36_bit") == 0 || strcasecmp(value, "36") == 0) { } else if (strcasecmp(value, "36_bit") == 0 || strcasecmp(value, "36") == 0) {
return impl::OverrideStatusFlag_AddressSpace64BitDeprecated; return impl::OverrideStatusFlag_AddressSpace64BitDeprecated;
} else if (strcasecmp(value, "32_bit") == 0 || strcasecmp(value, "32") == 0) { } else if (strcasecmp(value, "32_bit") == 0 || strcasecmp(value, "32") == 0) {
@@ -28,7 +28,9 @@ namespace ams::osdbg::impl {
constexpr inline bool IsLp64(const ThreadInfo *info) { constexpr inline bool IsLp64(const ThreadInfo *info) {
const auto as = info->_debug_info_create_process.flags & svc::CreateProcessFlag_AddressSpaceMask; const auto as = info->_debug_info_create_process.flags & svc::CreateProcessFlag_AddressSpaceMask;
return as == svc::CreateProcessFlag_AddressSpace64Bit || as == svc::CreateProcessFlag_AddressSpace64BitDeprecated; return as == svc::CreateProcessFlag_AddressSpace64Bit
|| as == svc::CreateProcessFlag_AddressSpace64BitDeprecated
|| as == svc::CreateProcessFlag_AddressSpace64Bit64KPage;
} }
constexpr inline bool Is64BitArch(const ThreadInfo *info) { constexpr inline bool Is64BitArch(const ThreadInfo *info) {
@@ -37,6 +37,13 @@ namespace ams::svc {
constexpr inline size_t AddressMemoryRegion39Size = 512_GB; constexpr inline size_t AddressMemoryRegion39Size = 512_GB;
constexpr inline size_t AddressMemoryRegionSmall42Size = 64_GB;
constexpr inline size_t AddressMemoryRegionAlias42Size = 512_GB;
constexpr inline size_t AddressMemoryRegionStack42Size = 2_GB;
constexpr inline size_t AddressMemoryRegion42Size = 4096_GB;
constexpr inline size_t AddressShadowStackRegionSize = 4_GB;
#elif defined(ATMOSPHERE_ARCH_ARM) #elif defined(ATMOSPHERE_ARCH_ARM)
constexpr inline size_t AddressMemoryRegionSmall32Size = 512_MB; constexpr inline size_t AddressMemoryRegionSmall32Size = 512_MB;
@@ -56,6 +63,12 @@ namespace ams::svc {
constexpr inline size_t AddressMemoryRegion39Size = 0; constexpr inline size_t AddressMemoryRegion39Size = 0;
constexpr inline size_t AddressMemoryRegionSmall42Size = 0;
constexpr inline size_t AddressMemoryRegionAlias42Size = 0;
constexpr inline size_t AddressMemoryRegionStack42Size = 0;
constexpr inline size_t AddressMemoryRegion42Size = 0;
#else #else
#error "Unknown architecture for svc::AddressMemoryRegion*Size" #error "Unknown architecture for svc::AddressMemoryRegion*Size"
@@ -97,4 +110,7 @@ namespace ams::svc {
constexpr inline uintptr_t AddressMap39End = AddressMemoryRegion39Size; constexpr inline uintptr_t AddressMap39End = AddressMemoryRegion39Size;
constexpr inline size_t AddressMap39Size = AddressMap39End - AddressMap39Start; constexpr inline size_t AddressMap39Size = AddressMap39End - AddressMap39Start;
constexpr inline uintptr_t AddressMap42Start = 0 + AddressNullGuard64Size;
constexpr inline uintptr_t AddressMap42End = AddressMemoryRegion42Size;
constexpr inline size_t AddressMap42Size = AddressMap42End - AddressMap42Start;
} }
@@ -191,8 +191,16 @@ namespace ams::svc {
InfoType_IsSvcPermitted = 26, InfoType_IsSvcPermitted = 26,
InfoType_IoRegionHint = 27, InfoType_IoRegionHint = 27,
InfoType_AliasRegionExtraSize = 28, InfoType_AliasRegionExtraSize = 28,
/* ... */ InfoType_RemoteRegionAddress = 29,
InfoType_RemoteRegionSize = 30,
InfoType_RemoteMemorySize = 31,
InfoType_RemoteMemoryUsageMax = 32,
InfoType_AllocateAlignment = 33,
InfoType_TransferMemoryHint = 34, InfoType_TransferMemoryHint = 34,
/* ... */
InfoType_AddressSpaceSize = 36,
InfoType_ShadowStackRegionAddress = 37,
InfoType_ShadowStackRegionSize = 38,
InfoType_MesosphereMeta = 65000, InfoType_MesosphereMeta = 65000,
InfoType_MesosphereCurrentProcess = 65001, InfoType_MesosphereCurrentProcess = 65001,
@@ -408,11 +416,12 @@ namespace ams::svc {
/* What kind of address space? */ /* What kind of address space? */
CreateProcessFlag_AddressSpaceShift = 1, CreateProcessFlag_AddressSpaceShift = 1,
CreateProcessFlag_AddressSpaceMask = (7 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpaceMask = (7 << CreateProcessFlag_AddressSpaceShift), /* Should be 15 but Nintendo didn't make 64K isn't usable yet */
CreateProcessFlag_AddressSpace32Bit = (0 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpace32Bit = (0 << CreateProcessFlag_AddressSpaceShift),
CreateProcessFlag_AddressSpace64BitDeprecated = (1 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpace64BitDeprecated = (1 << CreateProcessFlag_AddressSpaceShift),
CreateProcessFlag_AddressSpace32BitWithoutAlias = (2 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpace32BitWithoutAlias = (2 << CreateProcessFlag_AddressSpaceShift),
CreateProcessFlag_AddressSpace64Bit = (3 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpace64Bit = (3 << CreateProcessFlag_AddressSpaceShift),
CreateProcessFlag_AddressSpace64Bit64KPage = (4 << CreateProcessFlag_AddressSpaceShift),
/* Should JIT debug be done on crash? */ /* Should JIT debug be done on crash? */
CreateProcessFlag_EnableDebug = (1 << 4), CreateProcessFlag_EnableDebug = (1 << 4),
@@ -443,6 +452,9 @@ namespace ams::svc {
/* 18.x EnableAliasRegionExtraSize. */ /* 18.x EnableAliasRegionExtraSize. */
CreateProcessFlag_EnableAliasRegionExtraSize = (1 << 13), CreateProcessFlag_EnableAliasRegionExtraSize = (1 << 13),
/* 23.x EnableShadowStack. */
CreateProcessFlag_EnableShadowStack = (1 << 17),
/* Mask of all flags. */ /* Mask of all flags. */
CreateProcessFlag_All = CreateProcessFlag_Is64Bit | CreateProcessFlag_All = CreateProcessFlag_Is64Bit |
CreateProcessFlag_AddressSpaceMask | CreateProcessFlag_AddressSpaceMask |
@@ -452,7 +464,8 @@ namespace ams::svc {
CreateProcessFlag_PoolPartitionMask | CreateProcessFlag_PoolPartitionMask |
CreateProcessFlag_OptimizeMemoryAllocation | CreateProcessFlag_OptimizeMemoryAllocation |
CreateProcessFlag_DisableDeviceAddressSpaceMerge | CreateProcessFlag_DisableDeviceAddressSpaceMerge |
CreateProcessFlag_EnableAliasRegionExtraSize, CreateProcessFlag_EnableAliasRegionExtraSize |
CreateProcessFlag_EnableShadowStack,
}; };
/* Debug types. */ /* Debug types. */
@@ -57,7 +57,7 @@ namespace ams::svc {
/* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */ /* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */
/* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */ /* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(22); constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(23);
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 2); constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 2);
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion); constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
@@ -224,15 +224,20 @@ namespace ams::kern::init {
static_assert(kern::arch::arm64::init::IsInitialPageAllocator<KInitialPageAllocatorForFinalizeIdentityMapping>); static_assert(kern::arch::arm64::init::IsInitialPageAllocator<KInitialPageAllocatorForFinalizeIdentityMapping>);
void SetupAllTtbr0Entries(KInitialPageTable &init_pt, KInitialPageAllocator &allocator) { void SetupAllTtbr0Entries(KInitialPageTable &init_pt, KInitialPageAllocator &allocator) {
/* Validate that the ttbr0 array is in rodata. */ /* Validate that the ttbr0/tcr_el1 arrays are in rodata. */
const uintptr_t rodata_start = reinterpret_cast<uintptr_t>(__rodata_start); const uintptr_t rodata_start = reinterpret_cast<uintptr_t>(__rodata_start);
const uintptr_t rodata_end = reinterpret_cast<uintptr_t>(__rodata_end); const uintptr_t rodata_end = reinterpret_cast<uintptr_t>(__rodata_end);
MESOSPHERE_INIT_ABORT_UNLESS(rodata_start < rodata_end); MESOSPHERE_INIT_ABORT_UNLESS(rodata_start < rodata_end);
MESOSPHERE_INIT_ABORT_UNLESS(rodata_start <= reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTtbr0Entry(0)))); MESOSPHERE_INIT_ABORT_UNLESS(rodata_start <= reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTtbr0Entry(0))));
MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTtbr0Entry(KPageTable::NumTtbr0Entries))) < rodata_end); MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTtbr0Entry(KPageTable::NumPTEntries))) < rodata_end);
MESOSPHERE_INIT_ABORT_UNLESS(rodata_start <= reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTcrEL1Entry(0))));
MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTcrEL1Entry(KPageTable::NumPTEntries))) < rodata_end);
/* Get the default tcr_el1 value, with T0SZ set for a 39-bit address space. */
const u64 tcr_el1 = (cpu::GetTcrEl1() & ~UINT64_C(0x3F)) | UINT64_C(64 - 39);
/* Allocate pages for all ttbr0 entries. */ /* Allocate pages for all ttbr0 entries. */
for (size_t i = 0; i < KPageTable::NumTtbr0Entries; ++i) { for (size_t i = 0; i < KPageTable::NumPTEntries; ++i) {
/* Allocate a page. */ /* Allocate a page. */
KPhysicalAddress page = allocator.Allocate(PageSize); KPhysicalAddress page = allocator.Allocate(PageSize);
MESOSPHERE_INIT_ABORT_UNLESS(page != Null<KPhysicalAddress>); MESOSPHERE_INIT_ABORT_UNLESS(page != Null<KPhysicalAddress>);
@@ -245,6 +250,12 @@ namespace ams::kern::init {
/* Set the entry to the newly allocated page. */ /* Set the entry to the newly allocated page. */
*reinterpret_cast<volatile u64 *>(GetInteger(ttbr0_phys_ptr)) = (static_cast<u64>(i) << 48) | GetInteger(page); *reinterpret_cast<volatile u64 *>(GetInteger(ttbr0_phys_ptr)) = (static_cast<u64>(i) << 48) | GetInteger(page);
/* Get the physical address of the tcr_el1 entry. */
const auto tcr_el1_phys_ptr = init_pt.GetPhysicalAddress(KVirtualAddress(std::addressof(KPageTable::GetTcrEL1Entry(i))));
/* Set the entry to the default tcr_el1 value. */
*reinterpret_cast<volatile u64 *>(GetInteger(tcr_el1_phys_ptr)) = tcr_el1;
} }
} }
+1
View File
@@ -270,6 +270,7 @@ namespace ams::ldr {
case cfg::impl::OverrideStatusFlag_AddressSpace64BitDeprecated: meta->npdm->flags |= (Npdm::AddressSpaceType_64BitDeprecated) << Npdm::MetaFlag_AddressSpaceTypeShift; break; case cfg::impl::OverrideStatusFlag_AddressSpace64BitDeprecated: meta->npdm->flags |= (Npdm::AddressSpaceType_64BitDeprecated) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias: meta->npdm->flags |= (Npdm::AddressSpaceType_32BitWithoutAlias) << Npdm::MetaFlag_AddressSpaceTypeShift; break; case cfg::impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias: meta->npdm->flags |= (Npdm::AddressSpaceType_32BitWithoutAlias) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace64Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break; case cfg::impl::OverrideStatusFlag_AddressSpace64Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace64Bit64KPage: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit64KPage) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }
} }
@@ -423,6 +423,9 @@ namespace ams::ldr {
case Npdm::AddressSpaceType_64Bit: case Npdm::AddressSpaceType_64Bit:
flags |= svc::CreateProcessFlag_AddressSpace64Bit; flags |= svc::CreateProcessFlag_AddressSpace64Bit;
break; break;
case Npdm::AddressSpaceType_64Bit64KPage:
flags |= svc::CreateProcessFlag_AddressSpace64Bit64KPage;
break;
default: default:
R_THROW(ldr::ResultInvalidMeta()); R_THROW(ldr::ResultInvalidMeta());
} }
@@ -597,6 +600,10 @@ namespace ams::ldr {
aslr_start = svc::AddressMap39Start; aslr_start = svc::AddressMap39Start;
aslr_size = svc::AddressMap39Size; aslr_size = svc::AddressMap39Size;
break; break;
case svc::CreateProcessFlag_AddressSpace64Bit64KPage:
aslr_start = svc::AddressMap42Start;
aslr_size = svc::AddressMap42Size;
break;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }
} else { } else {