From e8ffbe630fcc7e187514c0345123d78bdf1a2691 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 25 Aug 2020 18:10:58 -0700 Subject: [PATCH] kern: support 2-pool layout on 2.x-4.x instead of modern 4-pool layout --- .../mesosphere/kern_initial_process.hpp | 1 + .../nintendo/nx/kern_k_system_control.cpp | 4 +- .../source/kern_initial_process.cpp | 38 ++++- ...kern_k_memory_layout.board.nintendo_nx.cpp | 158 ++++++++++++------ .../libmesosphere/source/kern_kernel.cpp | 16 +- .../source/svc/kern_svc_process.cpp | 60 ++++--- .../pm/source/impl/pm_resource_manager.cpp | 19 +++ 7 files changed, 204 insertions(+), 92 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp index 7e87cca96..bc15b0b88 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp @@ -34,5 +34,6 @@ namespace ams::kern { u64 GetInitialProcessIdMin(); u64 GetInitialProcessIdMax(); + size_t GetInitialProcessesSecureMemorySize(); } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index 648284436..ce872df9e 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -469,7 +469,7 @@ namespace ams::kern::board::nintendo::nx { KSleepManager::Initialize(); /* Reserve secure applet memory. */ - { + if (GetTargetFirmware() >= TargetFirmware_5_0_0) { MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null); MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletMemorySize)); @@ -486,7 +486,7 @@ namespace ams::kern::board::nintendo::nx { } u32 KSystemControl::GetInitialProcessBinaryPool() { - return KMemoryManager::Pool_Application; + return KMemoryManager::Pool_Unsafe; } /* Privileged Access. */ diff --git a/libraries/libmesosphere/source/kern_initial_process.cpp b/libraries/libmesosphere/source/kern_initial_process.cpp index ff0658be6..c5b4cbe14 100644 --- a/libraries/libmesosphere/source/kern_initial_process.cpp +++ b/libraries/libmesosphere/source/kern_initial_process.cpp @@ -38,6 +38,30 @@ namespace ams::kern { MESOSPHERE_ABORT_UNLESS(header->num_processes <= init::GetSlabResourceCounts().num_KProcess); } + size_t GetProcessesSecureMemorySize(KVirtualAddress binary_address, const InitialProcessBinaryHeader &header) { + u8 *current = GetPointer(binary_address + sizeof(InitialProcessBinaryHeader)); + const u8 * const end = GetPointer(binary_address + header.size - sizeof(KInitialProcessHeader)); + + size_t size = 0; + const size_t num_processes = header.num_processes; + for (size_t i = 0; i < num_processes; i++) { + /* Validate that we can read the current KIP. */ + MESOSPHERE_ABORT_UNLESS(current <= end); + KInitialProcessReader reader; + MESOSPHERE_ABORT_UNLESS(reader.Attach(current)); + + /* If the process uses secure memory, account for that. */ + if (reader.UsesSecureMemory()) { + size += util::AlignUp(reader.GetSize(), PageSize); + } + + /* Advance the reader. */ + current += reader.GetBinarySize(); + } + + return size; + } + void CreateProcesses(InitialProcessInfo *infos, KVirtualAddress binary_address, const InitialProcessBinaryHeader &header) { u8 *current = GetPointer(binary_address + sizeof(InitialProcessBinaryHeader)); const u8 * const end = GetPointer(binary_address + header.size - sizeof(KInitialProcessHeader)); @@ -108,10 +132,10 @@ namespace ams::kern { } } - KVirtualAddress g_initial_process_binary_address; - InitialProcessBinaryHeader g_initial_process_binary_header; - u64 g_initial_process_id_min = std::numeric_limits::max(); - u64 g_initial_process_id_max = std::numeric_limits::min(); + constinit KVirtualAddress g_initial_process_binary_address = Null; + constinit InitialProcessBinaryHeader g_initial_process_binary_header = {}; + constinit u64 g_initial_process_id_min = std::numeric_limits::max(); + constinit u64 g_initial_process_id_max = std::numeric_limits::min(); } @@ -123,6 +147,12 @@ namespace ams::kern { return g_initial_process_id_max; } + size_t GetInitialProcessesSecureMemorySize() { + LoadInitialProcessBinaryHeader(&g_initial_process_binary_header); + + return GetProcessesSecureMemorySize(g_initial_process_binary_address != Null ? g_initial_process_binary_address : GetInitialProcessBinaryAddress(), g_initial_process_binary_header); + } + void CopyInitialProcessBinaryToKernelMemory() { LoadInitialProcessBinaryHeader(&g_initial_process_binary_header); diff --git a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp index 071942bc7..781549236 100644 --- a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp @@ -59,31 +59,58 @@ namespace ams::kern { namespace init { - namespace { + void SetupDevicePhysicalMemoryRegions() { + /* TODO: Give these constexpr defines somewhere? */ + MESOSPHERE_INIT_ABORT_UNLESS(SetupUartPhysicalMemoryRegion()); + MESOSPHERE_INIT_ABORT_UNLESS(SetupPowerManagementControllerMemoryRegion()); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50041000, 0x1000, KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50042000, 0x1000, KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + } - void SetupPoolPartitionMemoryRegionsImpl() { - /* Start by identifying the extents of the DRAM memory region. */ - const auto dram_extents = KMemoryLayout::GetMainMemoryPhysicalExtents(); + void SetupDramPhysicalMemoryRegions() { + const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize(); + const KPhysicalAddress physical_memory_base_address = KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress); - const uintptr_t pool_end = dram_extents.GetEndAddress() - KTraceBufferSize; + /* Insert blocks into the tree. */ + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly)); + } + + void SetupPoolPartitionMemoryRegions() { + /* Start by identifying the extents of the DRAM memory region. */ + const auto dram_extents = KMemoryLayout::GetMainMemoryPhysicalExtents(); + + /* Determine the end of the pool region. */ + const uintptr_t pool_end = dram_extents.GetEndAddress() - KTraceBufferSize; + + /* Find the start of the kernel DRAM region. */ + const KMemoryRegion *kernel_dram_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramKernelBase); + MESOSPHERE_INIT_ABORT_UNLESS(kernel_dram_region != nullptr); + + const uintptr_t kernel_dram_start = kernel_dram_region->GetAddress(); + MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(kernel_dram_start, CarveoutAlignment)); + + /* Find the start of the pool partitions region. */ + const KMemoryRegion *pool_partitions_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(KMemoryRegionType_DramPoolPartition, 0); + MESOSPHERE_INIT_ABORT_UNLESS(pool_partitions_region != nullptr); + const uintptr_t pool_partitions_start = pool_partitions_region->GetAddress(); + + /* Setup the pool partition layouts. */ + if (GetTargetFirmware() >= TargetFirmware_5_0_0) { + /* On 5.0.0+, setup modern 4-pool-partition layout. */ /* Get Application and Applet pool sizes. */ const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize(); const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize(); const size_t unsafe_system_pool_min_size = KSystemControl::Init::GetMinimumNonSecureSystemPoolSize(); - /* Find the start of the kernel DRAM region. */ - const KMemoryRegion *kernel_dram_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramKernelBase); - MESOSPHERE_INIT_ABORT_UNLESS(kernel_dram_region != nullptr); - - const uintptr_t kernel_dram_start = kernel_dram_region->GetAddress(); - MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(kernel_dram_start, CarveoutAlignment)); - - /* Find the start of the pool partitions region. */ - const KMemoryRegion *pool_partitions_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(KMemoryRegionType_DramPoolPartition, 0); - MESOSPHERE_INIT_ABORT_UNLESS(pool_partitions_region != nullptr); - const uintptr_t pool_partitions_start = pool_partitions_region->GetAddress(); - /* Decide on starting addresses for our pools. */ const uintptr_t application_pool_start = pool_end - application_pool_size; const uintptr_t applet_pool_start = application_pool_start - applet_pool_size; @@ -124,45 +151,66 @@ namespace ams::kern { /* Insert the system pool. */ const uintptr_t system_pool_size = pool_management_start - pool_partitions_start; InsertPoolPartitionRegionIntoBothTrees(pool_partitions_start, system_pool_size, KMemoryRegionType_DramSystemPool, KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr); - } - - void SetupPoolPartitionMemoryRegionsDeprecatedImpl() { - MESOSPHERE_UNIMPLEMENTED(); - } - - } - - void SetupDevicePhysicalMemoryRegions() { - /* TODO: Give these constexpr defines somewhere? */ - MESOSPHERE_INIT_ABORT_UNLESS(SetupUartPhysicalMemoryRegion()); - MESOSPHERE_INIT_ABORT_UNLESS(SetupPowerManagementControllerMemoryRegion()); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50041000, 0x1000, KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50042000, 0x1000, KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - } - - void SetupDramPhysicalMemoryRegions() { - const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize(); - const KPhysicalAddress physical_memory_base_address = KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress); - - /* Insert blocks into the tree. */ - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly)); - } - - void SetupPoolPartitionMemoryRegions() { - if (GetTargetFirmware() >= TargetFirmware_5_0_0) { - /* On 5.0.0+, setup modern 4-pool-partition layout. */ - SetupPoolPartitionMemoryRegionsImpl(); - } else { + } else if (GetTargetFirmware() >= TargetFirmware_2_0_0) { /* On < 5.0.0, setup a legacy 2-pool layout for backwards compatibility. */ - SetupPoolPartitionMemoryRegionsDeprecatedImpl(); + + static_assert(KMemoryManager::Pool_Count == 4); + static_assert(KMemoryManager::Pool_Unsafe == KMemoryManager::Pool_Application); + static_assert(KMemoryManager::Pool_Secure == KMemoryManager::Pool_System); + + /* Get Secure pool size. */ + constexpr size_t LegacySecureKernelSize = 6_MB; /* KPageBuffer pages, other small kernel allocations. */ + constexpr size_t LegacySecureMiscSize = 1_MB; /* Miscellaneous pages for secure process mapping. */ + constexpr size_t LegacySecureHeapSize = 24_MB; /* Heap pages for secure process mapping (fs). */ + constexpr size_t LegacySecureEsSize = 1_MB + 232_KB; /* Size for additional secure process (es, 4.0.0+). */ + + const size_t secure_pool_size = GetInitialProcessesSecureMemorySize() + LegacySecureKernelSize + LegacySecureHeapSize + LegacySecureMiscSize + (GetTargetFirmware() >= TargetFirmware_4_0_0 ? LegacySecureEsSize : 0); + + /* Calculate the overhead for the secure and (defunct) applet/non-secure-system pools. */ + size_t total_overhead_size = KMemoryManager::CalculateManagementOverheadSize(secure_pool_size); + + /* Calculate the overhead for (an amount larger than) the unsafe pool. */ + const size_t approximate_total_overhead_size = total_overhead_size + KMemoryManager::CalculateManagementOverheadSize((pool_end - pool_partitions_start) - secure_pool_size - total_overhead_size) + 2 * PageSize; + + /* Determine the start of the unsafe region. */ + const uintptr_t unsafe_memory_start = util::AlignUp(pool_partitions_start + secure_pool_size + approximate_total_overhead_size, CarveoutAlignment); + + /* Determine the start of the pool regions. */ + const uintptr_t application_pool_start = unsafe_memory_start; + + /* Determine the pool sizes. */ + const size_t application_pool_size = pool_end - application_pool_start; + + /* We want to arrange application pool depending on where the middle of dram is. */ + const uintptr_t dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2; + u32 cur_pool_attr = 0; + if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) { + InsertPoolPartitionRegionIntoBothTrees(application_pool_start, application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); + total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(application_pool_size); + } else { + const size_t first_application_pool_size = dram_midpoint - application_pool_start; + const size_t second_application_pool_size = application_pool_start + application_pool_size - dram_midpoint; + InsertPoolPartitionRegionIntoBothTrees(application_pool_start, first_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); + InsertPoolPartitionRegionIntoBothTrees(dram_midpoint, second_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); + total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size); + total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size); + } + + /* Insert the secure pool. */ + InsertPoolPartitionRegionIntoBothTrees(pool_partitions_start, secure_pool_size, KMemoryRegionType_DramSystemPool, KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr); + + /* Insert the pool management region. */ + MESOSPHERE_INIT_ABORT_UNLESS(total_overhead_size <= approximate_total_overhead_size); + + const uintptr_t pool_management_start = pool_partitions_start + secure_pool_size; + const size_t pool_management_size = unsafe_memory_start - pool_management_start; + MESOSPHERE_INIT_ABORT_UNLESS(total_overhead_size <= pool_management_size); + + u32 pool_management_attr = 0; + InsertPoolPartitionRegionIntoBothTrees(pool_management_start, pool_management_size, KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement, pool_management_attr); + } else { + /* TODO: 1.0.0 single-pool layout. */ + MESOSPHERE_UNIMPLEMENTED(); } } diff --git a/libraries/libmesosphere/source/kern_kernel.cpp b/libraries/libmesosphere/source/kern_kernel.cpp index df80a1e17..750cc2a2f 100644 --- a/libraries/libmesosphere/source/kern_kernel.cpp +++ b/libraries/libmesosphere/source/kern_kernel.cpp @@ -152,11 +152,17 @@ namespace ams::kern { PrintMemoryRegion(" PageTableHeap", KMemoryLayout::GetKernelPageTableHeapRegionPhysicalExtents()); PrintMemoryRegion(" InitPageTable", KMemoryLayout::GetKernelInitPageTableRegionPhysicalExtents()); PrintMemoryRegion(" MemoryPoolRegion", KMemoryLayout::GetKernelPoolPartitionRegionPhysicalExtents()); - PrintMemoryRegion(" System", KMemoryLayout::GetKernelSystemPoolRegionPhysicalExtents()); - PrintMemoryRegion(" Management", KMemoryLayout::GetKernelPoolManagementRegionPhysicalExtents()); - PrintMemoryRegion(" SystemUnsafe", KMemoryLayout::GetKernelSystemNonSecurePoolRegionPhysicalExtents()); - PrintMemoryRegion(" Applet", KMemoryLayout::GetKernelAppletPoolRegionPhysicalExtents()); - PrintMemoryRegion(" Application", KMemoryLayout::GetKernelApplicationPoolRegionPhysicalExtents()); + if (GetTargetFirmware() >= TargetFirmware_5_0_0) { + PrintMemoryRegion(" System", KMemoryLayout::GetKernelSystemPoolRegionPhysicalExtents()); + PrintMemoryRegion(" Management", KMemoryLayout::GetKernelPoolManagementRegionPhysicalExtents()); + PrintMemoryRegion(" SystemUnsafe", KMemoryLayout::GetKernelSystemNonSecurePoolRegionPhysicalExtents()); + PrintMemoryRegion(" Applet", KMemoryLayout::GetKernelAppletPoolRegionPhysicalExtents()); + PrintMemoryRegion(" Application", KMemoryLayout::GetKernelApplicationPoolRegionPhysicalExtents()); + } else { + PrintMemoryRegion(" Secure", KMemoryLayout::GetKernelSystemPoolRegionPhysicalExtents()); + PrintMemoryRegion(" Management", KMemoryLayout::GetKernelPoolManagementRegionPhysicalExtents()); + PrintMemoryRegion(" Unsafe", KMemoryLayout::GetKernelApplicationPoolRegionPhysicalExtents()); + } if constexpr (IsKTraceEnabled) { MESOSPHERE_LOG(" Debug\n"); PrintMemoryRegion(" Trace Buffer", KMemoryLayout::GetKernelTraceBufferRegionPhysicalExtents()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 5369409ee..42bc9f63e 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -131,15 +131,16 @@ namespace ams::kern::svc { } /* Validate the pool partition. */ - /* TODO: 4.0.0 UseSecureMemory flag, pre-4.0.0 behavior. */ - switch (params.flags & ams::svc::CreateProcessFlag_PoolPartitionMask) { - case ams::svc::CreateProcessFlag_PoolPartitionApplication: - case ams::svc::CreateProcessFlag_PoolPartitionApplet: - case ams::svc::CreateProcessFlag_PoolPartitionSystem: - case ams::svc::CreateProcessFlag_PoolPartitionSystemNonSecure: - break; - default: - return svc::ResultInvalidEnumValue(); + if (GetTargetFirmware() >= TargetFirmware_5_0_0) { + switch (params.flags & ams::svc::CreateProcessFlag_PoolPartitionMask) { + case ams::svc::CreateProcessFlag_PoolPartitionApplication: + case ams::svc::CreateProcessFlag_PoolPartitionApplet: + case ams::svc::CreateProcessFlag_PoolPartitionSystem: + case ams::svc::CreateProcessFlag_PoolPartitionSystemNonSecure: + break; + default: + return svc::ResultInvalidEnumValue(); + } } /* Check that the code address is aligned. */ @@ -201,23 +202,30 @@ namespace ams::kern::svc { KResourceLimit *process_resource_limit = resource_limit.IsNotNull() ? resource_limit.GetPointerUnsafe() : std::addressof(Kernel::GetSystemResourceLimit()); /* Get the pool for the process. */ - /* TODO: 4.0.0 UseSecureMemory flag, pre-4.0.0 behavior. */ - KMemoryManager::Pool pool; - switch (params.flags & ams::svc::CreateProcessFlag_PoolPartitionMask) { - case ams::svc::CreateProcessFlag_PoolPartitionApplication: - pool = KMemoryManager::Pool_Application; - break; - case ams::svc::CreateProcessFlag_PoolPartitionApplet: - pool = KMemoryManager::Pool_Applet; - break; - case ams::svc::CreateProcessFlag_PoolPartitionSystem: - pool = KMemoryManager::Pool_System; - break; - case ams::svc::CreateProcessFlag_PoolPartitionSystemNonSecure: - default: - pool = KMemoryManager::Pool_SystemNonSecure; - break; - } + const auto pool = [] ALWAYS_INLINE_LAMBDA (u32 flags) -> KMemoryManager::Pool { + if (GetTargetFirmware() >= TargetFirmware_5_0_0) { + switch (flags & ams::svc::CreateProcessFlag_PoolPartitionMask) { + case ams::svc::CreateProcessFlag_PoolPartitionApplication: + return KMemoryManager::Pool_Application; + case ams::svc::CreateProcessFlag_PoolPartitionApplet: + return KMemoryManager::Pool_Applet; + case ams::svc::CreateProcessFlag_PoolPartitionSystem: + return KMemoryManager::Pool_System; + case ams::svc::CreateProcessFlag_PoolPartitionSystemNonSecure: + default: + return KMemoryManager::Pool_SystemNonSecure; + } + } else if (GetTargetFirmware() >= TargetFirmware_4_0_0) { + if ((flags & ams::svc::CreateProcessFlag_DeprecatedUseSecureMemory) != 0) { + return KMemoryManager::Pool_Secure; + } else { + return KMemoryManager::Pool_Unsafe; + } + } else { + return KMemoryManager::Pool_Unsafe; + } + }(params.flags); + /* Initialize the process. */ R_TRY(process->Initialize(params, user_caps, num_caps, process_resource_limit, pool)); diff --git a/stratosphere/pm/source/impl/pm_resource_manager.cpp b/stratosphere/pm/source/impl/pm_resource_manager.cpp index 7e31c4921..9a726ced4 100644 --- a/stratosphere/pm/source/impl/pm_resource_manager.cpp +++ b/stratosphere/pm/source/impl/pm_resource_manager.cpp @@ -168,6 +168,17 @@ namespace ams::pm::resource { } } + bool IsKTraceEnabled() { + if (!svc::IsKernelMesosphere()) { + return false; + } + + u64 value = 0; + R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), svc::InfoType_MesosphereMeta, INVALID_HANDLE, svc::MesosphereMetaInfo_IsKTraceEnabled)); + + return value != 0; + } + } /* Resource API. */ @@ -265,6 +276,14 @@ namespace ams::pm::resource { g_memory_resource_limits[i][ResourceLimitGroup_System] += extra_memory_size; g_memory_resource_limits[i][src_group] -= extra_memory_size; } + + /* If KTrace is enabled, account for that by subtracting the memory from the applet pool. */ + if (IsKTraceEnabled()) { + constexpr size_t KTraceBufferSize = 16_MB; + for (size_t i = 0; i < spl::MemoryArrangement_Count; i++) { + g_memory_resource_limits[i][ResourceLimitGroup_Applet] -= KTraceBufferSize; + } + } } /* Actually set resource limits. */