Merge pull request #2844 from alula/23_support

23.0.0: kernel changes
This commit is contained in:
hexkyz
2026-09-17 00:36:07 +01:00
committed by GitHub
42 changed files with 410 additions and 284 deletions

View File

@@ -81,6 +81,7 @@ namespace ams::kern::arch::arm64::cpu {
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpEl0, sp_el0)
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(PmUserEnrEl0, pmuserenr_el0)

View File

@@ -19,6 +19,7 @@
#include <mesosphere/kern_k_page_table_base.hpp>
#include <mesosphere/kern_k_page_group.hpp>
#include <mesosphere/kern_k_page_table_manager.hpp>
#include <mesosphere/init/kern_init_slab_setup.hpp>
namespace ams::kern::arch::arm64 {
@@ -94,10 +95,10 @@ namespace ams::kern::arch::arm64 {
return KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(KPageTable::GetBlockType(alignment) + 1));
}
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 NumTtbr0Entries = 81;
static constexpr size_t NumPTEntries = ::ams::kern::init::SlabCountKProcess + 1; /* +1 for kernel. */
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:
KPageTableManager *m_manager;
u8 m_asid;
@@ -188,6 +189,12 @@ namespace ams::kern::arch::arm64 {
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() {
/* Activate, using asid 0 and process id = 0xFFFFFFFF */
cpu::SwitchProcess(GetKernelTtbr0(), 0xFFFFFFFF);

View File

@@ -32,6 +32,11 @@ namespace ams::kern::arch::arm64 {
R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit, process_index));
}
static ALWAYS_INLINE u64 GetProcessTcrEl1(size_t process_index) {
/* The kernel's root table is entry zero; processes are indexed from one. */
return KPageTable::GetTcrEL1Entry(process_index + 1);
}
void Finalize() { m_page_table.Finalize(); }
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
@@ -302,19 +307,25 @@ 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, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); }
KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); }
KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); }
KProcessAddress GetAliasRegionStart() const { return m_page_table.GetAliasRegionStart(); }
KProcessAddress GetStackRegionStart() const { return m_page_table.GetStackRegionStart(); }
KProcessAddress GetKernelMapRegionStart() const { return m_page_table.GetKernelMapRegionStart(); }
KProcessAddress GetAliasCodeRegionStart() const { return m_page_table.GetAliasCodeRegionStart(); }
bool IsInShadowStackRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInShadowStackRegion(addr, size); }
bool IsInShadowStackRegion(KProcessAddress addr) const { return m_page_table.IsInShadowStackRegion(addr); }
bool IsSafeUserPointer(KProcessAddress addr, size_t size) const { return m_page_table.IsSafeUserPointer(addr, size); }
size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); }
size_t GetHeapRegionSize() const { return m_page_table.GetHeapRegionSize(); }
size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); }
size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); }
size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); }
size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); }
KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); }
KProcessAddress GetShadowStackRegionStart() const { return m_page_table.GetShadowStackRegionStart(); }
KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); }
KProcessAddress GetAliasRegionStart() const { return m_page_table.GetAliasRegionStart(); }
KProcessAddress GetStackRegionStart() const { return m_page_table.GetStackRegionStart(); }
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 GetShadowStackRegionSize() const { return m_page_table.GetShadowStackRegionSize(); }
size_t GetHeapRegionSize() const { return m_page_table.GetHeapRegionSize(); }
size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); }
size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); }
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(); }

View File

@@ -77,7 +77,7 @@ namespace ams::kern::arch::arm64 {
static bool CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src) {
/* Check that the address is within the valid userspace range. */
if (const uintptr_t src_uptr = reinterpret_cast<uintptr_t>(src); src_uptr < ams::svc::AddressNullGuard32Size || (src_uptr + sizeof(u32) - 1) >= ams::svc::AddressMemoryRegion39Size) {
if (const uintptr_t src_uptr = reinterpret_cast<uintptr_t>(src); src_uptr < ams::svc::AddressNullGuard32Size || (src_uptr + sizeof(u32) - 1) >= ams::svc::AddressMemoryRegion42Size) {
return false;
}

View File

@@ -18,6 +18,25 @@
#include <mesosphere/kern_k_slab_heap.hpp>
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 {
size_t num_KProcess;

View File

@@ -24,7 +24,7 @@ namespace ams::kern {
enum Type {
Type_MapSmall = 0,
Type_MapLarge = 1,
Type_Map39Bit = 2,
Type_MapHuge = 2,
Type_Heap = 3,
Type_Stack = 4,
Type_Alias = 5,

View File

@@ -211,15 +211,15 @@ namespace ams::kern {
uintptr_t m_address;
size_t m_size;
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;
KMemoryAttribute m_attribute;
KMemoryPermission m_original_permission;
u16 m_ipc_lock_count;
u16 m_device_use_count;
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 {
return {
@@ -365,15 +365,15 @@ namespace ams::kern {
.m_address = GetInteger(this->GetAddress()),
.m_size = this->GetSize(),
.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_attribute = m_attribute,
.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_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:

View File

@@ -90,10 +90,11 @@ namespace ams::kern {
};
enum RegionType {
RegionType_KernelMap = 0,
RegionType_Stack = 1,
RegionType_Alias = 2,
RegionType_Heap = 3,
RegionType_KernelMap = 0,
RegionType_Stack = 1,
RegionType_Alias = 2,
RegionType_Heap = 3,
RegionType_ShadowStack = 4,
RegionType_Count,
};
@@ -196,7 +197,6 @@ namespace ams::kern {
KPageTableImpl m_impl;
KMemoryBlockManager m_memory_block_manager;
u32 m_allocate_option;
u32 m_address_space_width;
bool m_is_kernel;
bool m_enable_aslr;
bool m_enable_device_address_space_merge;
@@ -212,23 +212,24 @@ namespace ams::kern {
public:
constexpr explicit KPageTableBase(util::ConstantInitializeTag)
: 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_ends{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>, 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_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_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
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_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()
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_general_lock(), m_map_physical_memory_lock(),
m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
m_allocate_option(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allowed_exec_device_mapping(),
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() { /* ... */ }
NOINLINE void InitializeForKernel(bool is_64_bit, 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 void InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
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();
@@ -247,6 +248,22 @@ namespace ams::kern {
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 {
const auto start = m_region_starts[RegionType_ShadowStack];
const auto end = m_region_ends[RegionType_ShadowStack];
return start != end && addr < end && start < addr + size;
}
constexpr bool IsInShadowStackRegion(KProcessAddress addr) const {
const auto start = m_region_starts[RegionType_ShadowStack];
const auto end = m_region_ends[RegionType_ShadowStack];
return start <= addr && addr < end;
}
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 {
/* 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);
@@ -490,19 +507,21 @@ namespace ams::kern {
public:
KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; }
KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; }
KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; }
KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; }
KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; }
KProcessAddress GetShadowStackRegionStart() const { return m_region_starts[RegionType_ShadowStack]; }
KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; }
KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; }
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; }
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 GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; }
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 GetShadowStackRegionSize() const { return m_region_ends[RegionType_ShadowStack] - m_region_starts[RegionType_ShadowStack]; }
size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; }
size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; }
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; }

View File

@@ -215,6 +215,7 @@ namespace ams::kern {
}
u32 GetAllocateOption() const { return m_page_table.GetAllocateOption(); }
size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); }
ThreadList &GetThreadList() { return m_thread_list; }
const ThreadList &GetThreadList() const { return m_thread_list; }

View File

@@ -341,6 +341,7 @@ namespace ams::kern {
bool m_debug_attached;
s8 m_priority_inheritance_count;
bool m_resource_limit_release_hint;
bool m_debug_unknown5;
public:
constexpr explicit KThread(util::ConstantInitializeTag)
: KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>(util::ConstantInitialize), KTimerTask(util::ConstantInitialize),
@@ -352,7 +353,7 @@ namespace ams::kern {
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},
m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{},
m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{},
m_cancellable{}, m_signaled{}, m_initialized{}, m_debug_attached{}, m_priority_inheritance_count{}, m_resource_limit_release_hint{}
m_cancellable{}, m_signaled{}, m_initialized{}, m_debug_attached{}, m_priority_inheritance_count{}, m_resource_limit_release_hint{}, m_debug_unknown5{}
{
/* ... */
}
@@ -683,6 +684,9 @@ namespace ams::kern {
constexpr void SetDebugAttached() { m_debug_attached = true; }
constexpr bool IsAttachedToDebugger() const { return m_debug_attached; }
constexpr void SetDebugUnknown5(bool value) { m_debug_unknown5 = value; }
constexpr bool IsDebugUnknown5() const { return m_debug_unknown5; }
void AddCpuTime(s32 core_id, s64 amount) {
m_cpu_time += amount;
/* TODO: Debug kernels track per-core tick counts. Should we? */

View File

@@ -125,7 +125,7 @@ namespace ams::kern::arch::arm64 {
m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer();
/* 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) {
@@ -144,7 +144,7 @@ namespace ams::kern::arch::arm64 {
const size_t as_width = GetAddressSpaceWidth(flags);
const KProcessAddress as_start = 0;
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). */
this->NoteUpdated();

View File

@@ -60,25 +60,6 @@ namespace ams::kern::init {
#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;
namespace test {

View File

@@ -30,15 +30,20 @@ namespace ams::kern {
{ 36, ams::svc::AddressLargeMap36Start, ams::svc::AddressLargeMap36Size, KAddressSpaceInfo::Type_MapLarge, },
{ 36, Invalid, ams::svc::AddressMemoryRegionHeap36Size, KAddressSpaceInfo::Type_Heap, },
{ 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::AddressMemoryRegionHeap39Size, KAddressSpaceInfo::Type_Heap, },
{ 39, Invalid, ams::svc::AddressMemoryRegionAlias39Size, KAddressSpaceInfo::Type_Alias, },
{ 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] = {
32, 36, 32, 39
constexpr u8 FlagsToAddressSpaceWidthTable[5] = {
32, 36, 32, 39, 42
};
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_AddressSpace32BitWithoutAlias) == 32);
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit) == 39);
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage) == 42);
KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
for (auto &info : AddressSpaceInfos) {

View File

@@ -100,8 +100,8 @@ namespace ams::kern {
KProcessPageTable &target_pt = process->GetPageTable();
/* Verify that the regions are in range. */
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(debugger_pt.IsSafeUserPointer(buffer, size), svc::ResultInvalidCurrentMemory());
/* Iterate over the target process's memory blocks. */
KProcessAddress cur_address = address;
@@ -166,8 +166,8 @@ namespace ams::kern {
KProcessPageTable &target_pt = process->GetPageTable();
/* Verify that the regions are in range. */
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(debugger_pt.IsSafeUserPointer(buffer, size), svc::ResultInvalidCurrentMemory());
/* Iterate over the target process's memory blocks. */
KProcessAddress cur_address = address;

View File

@@ -233,7 +233,7 @@ namespace ams::kern {
/* a number of pages here. Even though this is presumably only used for debug assertions, this is */
/* almost certainly a bug. */
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 size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type);
const uintptr_t map_end = map_start + map_size;

View File

@@ -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. */
m_address_space_width = (is_64_bit) ? BITSIZEOF(u64) : BITSIZEOF(u32);
m_address_space_start = KProcessAddress(GetInteger(start));
m_address_space_end = KProcessAddress(GetInteger(end));
m_is_kernel = true;
m_enable_aslr = true;
m_enable_device_address_space_merge = false;
m_allowed_exec_device_mapping = false;
for (auto i = 0; i < RegionType_Count; ++i) {
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));
}
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. */
MESOSPHERE_ABORT_UNLESS(start <= code_address);
MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size);
@@ -151,9 +151,9 @@ namespace ams::kern {
m_alias_region_extra_size = 0;
/* Set our width and heap/alias sizes. */
m_address_space_width = GetAddressSpaceWidth(flags);
size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias);
size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap);
size_t address_space_width = GetAddressSpaceWidth(flags);
size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias);
size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap);
/* Set code regions and determine remaining sizes. */
KProcessAddress process_code_start;
@@ -162,12 +162,12 @@ namespace ams::kern {
size_t kernel_map_region_size;
KProcessAddress before_process_code_start, after_process_code_start;
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);
kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall);
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Map39Bit);
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Map39Bit);
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_MapHuge);
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_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 (flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) {
/* 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;
}
@@ -208,6 +208,9 @@ namespace ams::kern {
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. */
m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 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 = 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. */
for (size_t i = 0; i < num_regions - 1; ++i) {
@@ -347,151 +353,36 @@ namespace ams::kern {
const KProcessAddress process_code_last = process_code_end - 1;
auto IsInAddressSpace = [&](KProcessAddress addr) ALWAYS_INLINE_LAMBDA { return m_address_space_start <= addr && addr <= m_address_space_end; };
/* Ensure that the KernelMap region is valid. */
for (size_t k = 0; k < num_regions; ++k) {
if (const auto &kmap_region = region_layouts[k]; kmap_region.type == RegionType_KernelMap) {
/* If there's no kmap region, we have nothing to check. */
if (kmap_region.size == 0) {
break;
}
/* Check that the kmap region is within our address space. */
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_KernelMap]));
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_KernelMap]));
/* Check for overlap with process code. */
const KProcessAddress kmap_start = m_region_starts[RegionType_KernelMap];
const KProcessAddress kmap_last = m_region_ends[RegionType_KernelMap] - 1;
MESOSPHERE_ABORT_UNLESS(kernel_map_region_size == 0 || kmap_last < process_code_start || process_code_last < kmap_start);
/* Check for overlap with stack. */
for (size_t s = 0; s < num_regions; ++s) {
if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) {
if (stack_region.size != 0) {
const KProcessAddress stack_start = m_region_starts[RegionType_Stack];
const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1;
MESOSPHERE_ABORT_UNLESS((kernel_map_region_size == 0 && stack_region_size == 0) || kmap_last < stack_start || stack_last < kmap_start);
}
break;
}
}
/* Check for overlap with alias. */
for (size_t a = 0; a < num_regions; ++a) {
if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) {
if (alias_region.size != 0) {
const KProcessAddress alias_start = m_region_starts[RegionType_Alias];
const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1;
MESOSPHERE_ABORT_UNLESS(kmap_last < alias_start || alias_last < kmap_start);
}
break;
}
}
/* Check for overlap with heap. */
for (size_t h = 0; h < num_regions; ++h) {
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
if (heap_region.size != 0) {
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
MESOSPHERE_ABORT_UNLESS(kmap_last < heap_start || heap_last < kmap_start);
}
break;
}
}
}
/* Map each region type to its layout entry. */
const RegionLayoutInfo *region_layouts_by_type[RegionType_Count] = {};
for (size_t i = 0; i < num_regions; ++i) {
region_layouts_by_type[region_layouts[i].type] = std::addressof(region_layouts[i]);
}
/* Check that the Stack region is valid. */
for (size_t s = 0; s < num_regions; ++s) {
if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) {
/* If there's no stack region, we have nothing to check. */
if (stack_region.size == 0) {
break;
}
/* Check that the stack region is within our address space. */
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Stack]));
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Stack]));
/* Check for overlap with process code. */
const KProcessAddress stack_start = m_region_starts[RegionType_Stack];
const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1;
MESOSPHERE_ABORT_UNLESS(stack_region_size == 0 || stack_last < process_code_start || process_code_last < stack_start);
/* Check for overlap with alias. */
for (size_t a = 0; a < num_regions; ++a) {
if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) {
if (alias_region.size != 0) {
const KProcessAddress alias_start = m_region_starts[RegionType_Alias];
const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1;
MESOSPHERE_ABORT_UNLESS(stack_last < alias_start || alias_last < stack_start);
}
break;
}
}
/* Check for overlap with heap. */
for (size_t h = 0; h < num_regions; ++h) {
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
if (heap_region.size != 0) {
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
MESOSPHERE_ABORT_UNLESS(stack_last < heap_start || heap_last < stack_start);
}
break;
}
}
/* Validate each region. */
for (size_t i = 0; i < RegionType_Count; ++i) {
/* If the region isn't present, there's nothing to check. */
const RegionLayoutInfo * const region = region_layouts_by_type[i];
if (region == nullptr || region->size == 0) {
continue;
}
}
/* Check that the Alias region is valid. */
for (size_t a = 0; a < num_regions; ++a) {
if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) {
/* If there's no alias region, we have nothing to check. */
if (alias_region.size == 0) {
break;
/* Check that the region is within our address space. */
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[i]));
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[i]));
/* Check for overlap with process code. */
MESOSPHERE_ABORT_UNLESS(m_region_ends[i] - 1 < process_code_start || process_code_last < m_region_starts[i]);
/* Check for overlap with every later region. */
for (size_t j = i; j < RegionType_ShadowStack; ++j) {
/* If the other region isn't present, there's nothing to check. */
const RegionLayoutInfo * const other = region_layouts_by_type[j + 1];
if (other == nullptr || other->size == 0) {
continue;
}
/* Check that the alias region is within our address space. */
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Alias]));
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Alias]));
/* Check for overlap with process code. */
const KProcessAddress alias_start = m_region_starts[RegionType_Alias];
const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1;
MESOSPHERE_ABORT_UNLESS(alias_last < process_code_start || process_code_last < alias_start);
/* Check for overlap with heap. */
for (size_t h = 0; h < num_regions; ++h) {
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
if (heap_region.size != 0) {
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
MESOSPHERE_ABORT_UNLESS(alias_last < heap_start || heap_last < alias_start);
}
break;
}
}
}
}
/* Check that the Heap region is valid. */
for (size_t h = 0; h < num_regions; ++h) {
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
/* If there's no heap region, we have nothing to check. */
if (heap_region.size == 0) {
break;
}
/* Check that the heap region is within our address space. */
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Heap]));
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Heap]));
/* Check for overlap with process code. */
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
MESOSPHERE_ABORT_UNLESS(heap_last < process_code_start || process_code_last < heap_start);
MESOSPHERE_ABORT_UNLESS(m_region_ends[i] - 1 < m_region_starts[j + 1] || m_region_ends[j + 1] - 1 < m_region_starts[i]);
}
}
}
@@ -561,6 +452,8 @@ namespace ams::kern {
case ams::svc::MemoryState_Static:
case ams::svc::MemoryState_ThreadLocal:
return m_region_starts[RegionType_KernelMap];
case ams::svc::MemoryState_ShadowStack:
return m_region_starts[RegionType_ShadowStack];
case ams::svc::MemoryState_Io:
case ams::svc::MemoryState_Shared:
case ams::svc::MemoryState_AliasCode:
@@ -596,6 +489,8 @@ namespace ams::kern {
case ams::svc::MemoryState_Static:
case ams::svc::MemoryState_ThreadLocal:
return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap];
case ams::svc::MemoryState_ShadowStack:
return m_region_ends[RegionType_ShadowStack] - m_region_starts[RegionType_ShadowStack];
case ams::svc::MemoryState_Io:
case ams::svc::MemoryState_Shared:
case ams::svc::MemoryState_AliasCode:
@@ -622,12 +517,20 @@ namespace ams::kern {
const KProcessAddress region_start = this->GetRegionAddress(state);
const size_t region_size = this->GetRegionSize(state);
if (region_size == 0) {
return false;
}
const bool is_in_region = region_start <= addr && addr < end && last <= region_start + region_size - 1;
const bool is_in_heap = !(end <= m_region_starts[RegionType_Heap] || m_region_ends[RegionType_Heap] <= addr || m_region_starts[RegionType_Heap] == m_region_ends[RegionType_Heap]);
const bool is_in_alias = !(end <= m_region_starts[RegionType_Alias] || m_region_ends[RegionType_Alias] <= addr || m_region_starts[RegionType_Alias] == m_region_ends[RegionType_Alias]);
switch (state) {
case ams::svc::MemoryState_Free:
case ams::svc::MemoryState_Normal:
case ams::svc::MemoryState_Ipc:
case ams::svc::MemoryState_NonSecureIpc:
case ams::svc::MemoryState_NonDeviceIpc:
case ams::svc::MemoryState_Kernel:
case ams::svc::MemoryState_ShadowStack:
return is_in_region;
case ams::svc::MemoryState_Io:
case ams::svc::MemoryState_Static:
@@ -645,17 +548,32 @@ namespace ams::kern {
case ams::svc::MemoryState_CodeOut:
case ams::svc::MemoryState_Coverage:
case ams::svc::MemoryState_Insecure:
return is_in_region && !is_in_heap && !is_in_alias;
case ams::svc::MemoryState_Normal:
MESOSPHERE_ASSERT(is_in_heap);
return is_in_region && !is_in_alias;
case ams::svc::MemoryState_Ipc:
case ams::svc::MemoryState_NonSecureIpc:
case ams::svc::MemoryState_NonDeviceIpc:
MESOSPHERE_ASSERT(is_in_alias);
return is_in_region && !is_in_heap;
default:
return false;
{
if (!is_in_region) {
return false;
}
const auto heap_start = m_region_starts[RegionType_Heap];
const auto heap_end = m_region_ends[RegionType_Heap];
if (heap_start != heap_end && addr < heap_end && heap_start < end) {
return false;
}
const auto alias_start = m_region_starts[RegionType_Alias];
const auto alias_end = m_region_ends[RegionType_Alias];
if (alias_start != alias_end && addr < alias_end && alias_start < end) {
return false;
}
const auto shadow_start = m_region_starts[RegionType_ShadowStack];
const auto shadow_end = m_region_ends[RegionType_ShadowStack];
if (shadow_start != shadow_end && addr < shadow_end && shadow_start < end) {
return false;
}
return true;
}
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
}
@@ -1997,15 +1915,15 @@ namespace ams::kern {
.m_address = GetInteger(m_address_space_end),
.m_size = 0 - GetInteger(m_address_space_end),
.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_attribute = KMemoryAttribute_None,
.m_original_permission = KMemoryPermission_None,
.m_ipc_lock_count = 0,
.m_device_use_count = 0,
.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;
@@ -3287,7 +3205,7 @@ namespace ams::kern {
Result KPageTableBase::CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
/* Lightly validate the range before doing anything else. */
R_UNLESS(this->Contains(src_addr, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(this->IsSafeUserPointer(src_addr, size), svc::ResultInvalidCurrentMemory());
/* Copy the memory. */
{
@@ -3436,7 +3354,7 @@ namespace ams::kern {
Result KPageTableBase::CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) {
/* Lightly validate the range before doing anything else. */
R_UNLESS(this->Contains(dst_addr, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(this->IsSafeUserPointer(dst_addr, size), svc::ResultInvalidCurrentMemory());
/* Copy the memory. */
{

View File

@@ -970,6 +970,9 @@ namespace ams::kern {
/* Initialize the thread. */
R_TRY(KThread::InitializeUserThread(main_thread, reinterpret_cast<KThreadFunction>(GetVoidPointer(this->GetEntryPoint())), 0, stack_top, priority, m_ideal_core_id, this));
/* TODO: what is this? */
main_thread->SetDebugUnknown5(true);
/* Register the thread, and commit our reservation. */
KThread::Register(main_thread);
thread_reservation.Commit();

View File

@@ -170,6 +170,13 @@ namespace ams::kern {
KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Alias, alias_size);
}
/* Update 42-bit address space infos. */
{
/* Heap should be equal to the total memory size, maximum 128 GB. */
/* Alias/Stack/MapSmall are left at their static defaults. */
KAddressSpaceInfo::SetAddressSpaceSize(42, KAddressSpaceInfo::Type_Heap, std::min(util::AlignUp(total_memory_size, 1_GB), 128_GB));
}
const auto &slab_counts = init::GetSlabResourceCounts();
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size));
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread));

View File

@@ -21,8 +21,10 @@ namespace ams::kern::svc {
namespace {
constexpr bool IsKernelAddress(uintptr_t address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
constexpr bool IsValidAddress(uintptr_t address) {
if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false;
if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false;
return true;
}
constexpr bool IsValidSignalType(ams::svc::SignalType type) {
@@ -50,7 +52,7 @@ namespace ams::kern::svc {
Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
/* Validate input. */
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidCurrentMemory());
if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) {
R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress());
} else {
@@ -79,7 +81,7 @@ namespace ams::kern::svc {
Result SignalToAddress(uintptr_t address, ams::svc::SignalType signal_type, int32_t value, int32_t count) {
/* Validate input. */
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidCurrentMemory());
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
R_UNLESS(IsValidSignalType(signal_type), svc::ResultInvalidEnumValue());

View File

@@ -83,7 +83,7 @@ namespace ams::kern::svc {
R_SUCCEED_IF(size == 0);
/* Validate that the region is within range. */
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(address, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(address, size), svc::ResultInvalidCurrentMemory()); /* did N intend ResultInvalidPointer like everywhere else? */
/* Flush the cache. */
R_TRY(cpu::FlushDataCache(reinterpret_cast<void *>(address), size));

View File

@@ -21,13 +21,15 @@ namespace ams::kern::svc {
namespace {
constexpr bool IsKernelAddress(uintptr_t address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
constexpr bool IsValidAddress(uintptr_t address) {
if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false;
if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false;
return true;
}
Result WaitProcessWideKeyAtomic(uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns) {
/* Validate input. */
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidPointer());
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
/* Convert timeout from nanoseconds to ticks. */

View File

@@ -97,6 +97,8 @@ namespace ams::kern::svc {
/* Only allow invoking the svc on development hardware or if force debug prod. */
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_info.GetUnsafePointer()), sizeof(EventInfoType)), svc::ResultInvalidPointer());
/* Get the debug object. */
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
@@ -139,6 +141,8 @@ namespace ams::kern::svc {
/* Verify that the number of thread ids is valid. */
R_UNLESS((0 <= num_thread_ids && num_thread_ids <= MaximumDebuggableThreadCount), svc::ResultOutOfRange());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_thread_ids.GetUnsafePointer()), num_thread_ids * sizeof(uint64_t)), svc::ResultInvalidPointer());
/* Copy the threads from userspace. */
uint64_t thread_ids[MaximumDebuggableThreadCount];
if (num_thread_ids > 0) {
@@ -172,6 +176,8 @@ namespace ams::kern::svc {
/* Only allow invoking the svc on development hardware or if force debug prod. */
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer());
/* Validate the context flags. */
R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue());
@@ -193,6 +199,8 @@ namespace ams::kern::svc {
/* Only allow invoking the svc on development hardware. */
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer());
/* Validate the context flags. */
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
{
@@ -243,6 +251,8 @@ namespace ams::kern::svc {
template<typename T>
Result QueryDebugProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uint64_t address) {
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_memory_info.GetUnsafePointer()), sizeof(T)), svc::ResultInvalidPointer());
/* Get an ams::svc::MemoryInfo for the region. */
ams::svc::MemoryInfo info = {};
R_TRY(QueryDebugProcessMemory(std::addressof(info), out_page_info, debug_handle, address));
@@ -429,6 +439,11 @@ namespace ams::kern::svc {
*out_32 = affinity_mask;
}
break;
case ams::svc::DebugThreadParam_Unknown5:
{
*out_32 = thread->IsDebugUnknown5();
}
break;
default:
R_THROW(ams::svc::ResultInvalidEnumValue());
}

View File

@@ -26,7 +26,7 @@ namespace ams::kern::svc {
R_SUCCEED_IF(len == 0);
/* Ensure that the data being output is in range. */
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(debug_str.GetUnsafePointer()), len), svc::ResultInvalidCurrentMemory());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(debug_str.GetUnsafePointer()), len), svc::ResultInvalidPointer());
/* Output the string. */
R_RETURN(KDebugLog::PrintUserString(debug_str, len));

View File

@@ -109,6 +109,15 @@ namespace ams::kern::svc {
case ams::svc::InfoType_AliasRegionExtraSize:
*out = process->GetPageTable().GetAliasRegionExtraSize();
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();
}
@@ -138,6 +147,9 @@ namespace ams::kern::svc {
case ams::svc::InfoType_IsApplication:
case ams::svc::InfoType_FreeThreadCount:
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. */
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());

View File

@@ -110,7 +110,7 @@ namespace ams::kern::svc {
/* Copy user handles. */
if (num_handles > 0) {
/* Ensure that we can try to get the handles. */
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
/* Get the handles. */
R_TRY(user_handles.CopyArrayTo(handles, num_handles));

View File

@@ -21,13 +21,15 @@ namespace ams::kern::svc {
namespace {
constexpr bool IsKernelAddress(uintptr_t address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
constexpr bool IsValidAddress(uintptr_t address) {
if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false;
if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false;
return true;
}
Result ArbitrateLock(ams::svc::Handle thread_handle, uintptr_t address, uint32_t tag) {
/* Validate the input address. */
R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory());
R_UNLESS(IsValidAddress(address), svc::ResultInvalidCurrentMemory());
R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress());
R_RETURN(KConditionVariable::WaitForAddress(thread_handle, address, tag));
@@ -35,7 +37,7 @@ namespace ams::kern::svc {
Result ArbitrateUnlock(uintptr_t address) {
/* Validate the input address. */
R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory());
R_UNLESS(IsValidAddress(address), svc::ResultInvalidCurrentMemory());
R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress());
R_RETURN(KConditionVariable::SignalToAddress(address));

View File

@@ -21,11 +21,22 @@ namespace ams::kern::svc {
namespace {
static Result GetPortName(char (&name)[KObjectName::NameLengthMax], KUserPointer<const char *> user_name) {
/* Copy the provided name from user memory to kernel memory. */
R_TRY(user_name.CopyStringTo(name, sizeof(name)));
/* Oddly enough N here first copies then validates if it's not in forbidden range. */
const auto name_len = util::Strnlen(name, sizeof(name));
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_name.GetUnsafePointer()), name_len + 1), svc::ResultInvalidPointer());
R_SUCCEED();
}
Result ManageNamedPort(ams::svc::Handle *out_server_handle, KUserPointer<const char *> user_name, s32 max_sessions) {
/* Copy the provided name from user memory to kernel memory. */
char name[KObjectName::NameLengthMax] = {};
R_TRY(user_name.CopyStringTo(name, sizeof(name)));
R_TRY(GetPortName(name, user_name));
/* Validate that sessions and name are valid. */
R_UNLESS(max_sessions >= 0, svc::ResultOutOfRange());
R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange());
@@ -106,7 +117,7 @@ namespace ams::kern::svc {
Result ConnectToNamedPort(ams::svc::Handle *out, KUserPointer<const char *> user_name) {
/* Copy the provided name from user memory to kernel memory. */
char name[KObjectName::NameLengthMax] = {};
R_TRY(user_name.CopyStringTo(name, sizeof(name)));
R_TRY(GetPortName(name, user_name));
/* Validate that name is valid. */
R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange());

View File

@@ -79,13 +79,47 @@ namespace ams::kern::svc {
/* Validate that the pointer is in range. */
if (max_out_count > 0) {
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_process_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_process_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidPointer());
}
/* Get the process list. */
R_RETURN(KProcess::GetProcessList(out_num_processes, out_process_ids, max_out_count));
}
constexpr size_t GetProcessSlotT0Sz(ams::svc::CreateProcessFlag flags) {
if ((flags & ams::svc::CreateProcessFlag_AddressSpaceMask) == ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage) {
return (64 - 42);
} else {
return (64 - 39);
}
}
KProcess *CreateProcessForAddressSpace(ams::svc::CreateProcessFlag flags) {
/* Find a process slab slot whose root page table is meant for the requested address space. */
const size_t desired_t0sz = GetProcessSlotT0Sz(flags);
KProcess *process = nullptr;
KProcess *rejected[init::SlabCountKProcess];
size_t num_rejected = 0;
while ((process = KProcess::Create()) != nullptr) {
/* Stop once we find a slot whose T0SZ matches. */
if ((KProcessPageTable::GetProcessTcrEl1(process->GetSlabIndex()) & 0x3F) == desired_t0sz) {
break;
}
/* Otherwise, park the process and try the next slot. */
rejected[num_rejected++] = process;
process = nullptr;
}
/* Release every process we parked while searching. */
for (size_t i = 0; i < num_rejected; ++i) {
rejected[i]->Close();
}
return process;
}
Result CreateProcess(ams::svc::Handle *out, const ams::svc::CreateProcessParameter &params, KUserPointer<const uint32_t *> user_caps, int32_t num_caps) {
/* Validate the capabilities pointer. */
R_UNLESS(num_caps >= 0, svc::ResultInvalidPointer());
@@ -94,12 +128,15 @@ namespace ams::kern::svc {
R_UNLESS(((num_caps * sizeof(u32)) / sizeof(u32)) == static_cast<size_t>(num_caps), svc::ResultInvalidPointer());
/* Validate that the pointer is in range. */
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_caps.GetUnsafePointer()), num_caps * sizeof(u32)), svc::ResultInvalidPointer());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_caps.GetUnsafePointer()), num_caps * sizeof(u32)), svc::ResultInvalidPointer());
}
/* Validate that the parameter flags are valid. */
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. */
const bool is_64_bit = (params.flags & ams::svc::CreateProcessFlag_Is64Bit) != 0;
if constexpr (sizeof(void *) < sizeof(u64)) {
@@ -130,12 +167,13 @@ namespace ams::kern::svc {
}
break;
case ams::svc::CreateProcessFlag_AddressSpace64Bit:
case ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage:
{
/* 64-bit address space requires 64-bit process. */
R_UNLESS(is_64_bit, svc::ResultInvalidCombination());
map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit, code_size);
map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit);
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_MapHuge);
map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Heap);
}
@@ -215,8 +253,8 @@ namespace ams::kern::svc {
/* Get the current handle table. */
auto &handle_table = GetCurrentProcess().GetHandleTable();
/* Create the new process. */
KProcess *process = KProcess::Create();
/* Create the new process, ensuring its page table slot matches the requested address space. */
KProcess *process = CreateProcessForAddressSpace(static_cast<ams::svc::CreateProcessFlag>(params.flags));
R_UNLESS(process != nullptr, svc::ResultOutOfResource());
/* Ensure that the only reference to the process is in the handle table when we're done. */

View File

@@ -148,7 +148,7 @@ namespace ams::kern::svc {
/* Validate that the mapping is in range. */
auto &page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory());
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion());
/* Map the memory. */
R_TRY(page_table.MapCodeMemory(dst_address, src_address, size));
@@ -175,7 +175,7 @@ namespace ams::kern::svc {
/* Validate that the mapping is in range. */
auto &page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory());
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory());
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion());
/* Unmap the memory. */
R_TRY(page_table.UnmapCodeMemory(dst_address, src_address, size));

View File

@@ -37,6 +37,8 @@ namespace ams::kern::svc {
template<typename T>
Result QueryProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uint64_t address) {
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_memory_info.GetUnsafePointer()), sizeof(T)), svc::ResultInvalidPointer());
/* Get an ams::svc::MemoryInfo for the region. */
ams::svc::MemoryInfo info = {};
R_TRY(QueryProcessMemory(std::addressof(info), out_page_info, process_handle, address));

View File

@@ -82,7 +82,7 @@ namespace ams::kern::svc {
/* Copy user handles. */
if (num_handles > 0) {
/* Ensure that we can try to get the handles. */
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
/* Get the handles. */
R_TRY(user_handles.CopyArrayTo(handles, num_handles));

View File

@@ -204,6 +204,8 @@ namespace ams::kern::svc {
/* Get the thread from its handle. */
KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer());
/* Require the handle be to a non-current thread in the current process. */
R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle());
@@ -228,7 +230,7 @@ namespace ams::kern::svc {
/* Validate that the pointer is in range. */
if (max_out_count > 0) {
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory());
R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidPointer());
}
/* Get the handle table. */

View File

@@ -35,6 +35,7 @@ namespace ams::cfg {
OverrideStatusFlag_AddressSpace64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> 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_AddressSpace64Bit64KPage = (svc::CreateProcessFlag_AddressSpace64Bit64KPage >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift,
#endif
};

View File

@@ -235,11 +235,16 @@ namespace ams::ldr {
MetaFlag_PreventCodeReads = (1 << 7),
};
enum MetaFlag2 {
MetaFlag2_EnableShadowStack = (1 << 0),
};
enum AddressSpaceType {
AddressSpaceType_32Bit = 0,
AddressSpaceType_64BitDeprecated = 1,
AddressSpaceType_32BitWithoutAlias = 2,
AddressSpaceType_64Bit = 3,
AddressSpaceType_64Bit64KPage = 4,
};
#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_32BitWithoutAlias == (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift));
static_assert(AddressSpaceType_64Bit == (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift));
static_assert(AddressSpaceType_64Bit64KPage == (svc::CreateProcessFlag_AddressSpace64Bit64KPage >> svc::CreateProcessFlag_AddressSpaceShift));
#endif
u32 magic;
u32 signature_key_generation;
u8 reserved_08[4];
u8 flags;
u8 reserved_0D;
u8 flags2;
u8 main_thread_priority;
u8 default_cpu_id;
u8 reserved_10[4];

View File

@@ -153,6 +153,8 @@ namespace ams::cfg {
impl::OverrideStatusFlag ParseOverrideAddressSpace(const char *value) {
if (strcasecmp(value, "39_bit") == 0 || strcasecmp(value, "39") == 0) {
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) {
return impl::OverrideStatusFlag_AddressSpace64BitDeprecated;
} else if (strcasecmp(value, "32_bit") == 0 || strcasecmp(value, "32") == 0) {

View File

@@ -28,7 +28,9 @@ namespace ams::osdbg::impl {
constexpr inline bool IsLp64(const ThreadInfo *info) {
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) {

View File

@@ -37,6 +37,13 @@ namespace ams::svc {
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)
constexpr inline size_t AddressMemoryRegionSmall32Size = 512_MB;
@@ -56,6 +63,12 @@ namespace ams::svc {
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
#error "Unknown architecture for svc::AddressMemoryRegion*Size"
@@ -97,4 +110,7 @@ namespace ams::svc {
constexpr inline uintptr_t AddressMap39End = AddressMemoryRegion39Size;
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;
}

View File

@@ -96,6 +96,9 @@ namespace ams::svc {
MemoryState_CodeOut = 0x15,
MemoryState_Coverage = 0x16,
MemoryState_Insecure = 0x17,
MemoryState_Remote = 0x18,
MemoryState_Protected = 0x19,
MemoryState_ShadowStack = 0x1A,
};
enum MemoryPermission : u32 {
@@ -191,8 +194,16 @@ namespace ams::svc {
InfoType_IsSvcPermitted = 26,
InfoType_IoRegionHint = 27,
InfoType_AliasRegionExtraSize = 28,
/* ... */
InfoType_RemoteRegionAddress = 29,
InfoType_RemoteRegionSize = 30,
InfoType_RemoteMemorySize = 31,
InfoType_RemoteMemoryUsageMax = 32,
InfoType_AllocateAlignment = 33,
InfoType_TransferMemoryHint = 34,
/* ... */
InfoType_AddressSpaceSize = 36,
InfoType_ShadowStackRegionAddress = 37,
InfoType_ShadowStackRegionSize = 38,
InfoType_MesosphereMeta = 65000,
InfoType_MesosphereCurrentProcess = 65001,
@@ -408,11 +419,12 @@ namespace ams::svc {
/* What kind of address space? */
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_AddressSpace64BitDeprecated = (1 << CreateProcessFlag_AddressSpaceShift),
CreateProcessFlag_AddressSpace32BitWithoutAlias = (2 << CreateProcessFlag_AddressSpaceShift),
CreateProcessFlag_AddressSpace64Bit = (3 << CreateProcessFlag_AddressSpaceShift),
CreateProcessFlag_AddressSpace64Bit64KPage = (4 << CreateProcessFlag_AddressSpaceShift),
/* Should JIT debug be done on crash? */
CreateProcessFlag_EnableDebug = (1 << 4),
@@ -443,6 +455,9 @@ namespace ams::svc {
/* 18.x EnableAliasRegionExtraSize. */
CreateProcessFlag_EnableAliasRegionExtraSize = (1 << 13),
/* 23.x EnableShadowStack. */
CreateProcessFlag_EnableShadowStack = (1 << 17),
/* Mask of all flags. */
CreateProcessFlag_All = CreateProcessFlag_Is64Bit |
CreateProcessFlag_AddressSpaceMask |
@@ -452,7 +467,8 @@ namespace ams::svc {
CreateProcessFlag_PoolPartitionMask |
CreateProcessFlag_OptimizeMemoryAllocation |
CreateProcessFlag_DisableDeviceAddressSpaceMerge |
CreateProcessFlag_EnableAliasRegionExtraSize,
CreateProcessFlag_EnableAliasRegionExtraSize |
CreateProcessFlag_EnableShadowStack,
};
/* Debug types. */
@@ -470,6 +486,7 @@ namespace ams::svc {
DebugThreadParam_IdealCore = 2,
DebugThreadParam_CurrentCore = 3,
DebugThreadParam_AffinityMask = 4,
DebugThreadParam_Unknown5 = 5,
};
enum DebugException : u32 {

View File

@@ -57,7 +57,7 @@ namespace ams::svc {
/* 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. */
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(22);
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(23);
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 2);
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);

View File

@@ -224,15 +224,20 @@ namespace ams::kern::init {
static_assert(kern::arch::arm64::init::IsInitialPageAllocator<KInitialPageAllocatorForFinalizeIdentityMapping>);
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_end = reinterpret_cast<uintptr_t>(__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(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)) | (64 - 39);
/* 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. */
KPhysicalAddress page = allocator.Allocate(PageSize);
MESOSPHERE_INIT_ABORT_UNLESS(page != Null<KPhysicalAddress>);
@@ -245,6 +250,12 @@ namespace ams::kern::init {
/* Set the entry to the newly allocated 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;
}
}

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_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_AddressSpace64Bit64KPage: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit64KPage) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}

View File

@@ -423,6 +423,9 @@ namespace ams::ldr {
case Npdm::AddressSpaceType_64Bit:
flags |= svc::CreateProcessFlag_AddressSpace64Bit;
break;
case Npdm::AddressSpaceType_64Bit64KPage:
flags |= svc::CreateProcessFlag_AddressSpace64Bit64KPage;
break;
default:
R_THROW(ldr::ResultInvalidMeta());
}
@@ -597,6 +600,10 @@ namespace ams::ldr {
aslr_start = svc::AddressMap39Start;
aslr_size = svc::AddressMap39Size;
break;
case svc::CreateProcessFlag_AddressSpace64Bit64KPage:
aslr_start = svc::AddressMap42Start;
aslr_size = svc::AddressMap42Size;
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
} else {