diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp index 0457381f6..afe704cfa 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp @@ -22,9 +22,9 @@ namespace ams::kern { struct KAddressSpaceInfo { public: enum Type { - Type_32Bit = 0, - Type_Small64Bit = 1, - Type_Large64Bit = 2, + Type_MapSmall = 0, + Type_MapLarge = 1, + Type_Map39Bit = 2, Type_Heap = 3, Type_Stack = 4, Type_Alias = 5, diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 780ad96bb..6b283ef51 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -48,6 +48,8 @@ namespace ams::kern { }; using ThreadList = util::IntrusiveListMemberTraits<&KThread::process_list_node>::ListType; + + static constexpr size_t AslrAlignment = KernelAslrAlignment; private: using SharedMemoryInfoList = util::IntrusiveListBaseTraits::ListType; using TLPTree = util::IntrusiveRedBlackTreeBaseTraits::TreeType; @@ -123,6 +125,7 @@ namespace ams::kern { virtual ~KProcess() { /* ... */ } Result Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool); + Result Initialize(const ams::svc::CreateProcessParameter ¶ms, svc::KUserPointer caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool); void Exit(); constexpr const char *GetName() const { return this->name; } diff --git a/libraries/libmesosphere/source/kern_k_address_space_info.cpp b/libraries/libmesosphere/source/kern_k_address_space_info.cpp index 1d81e14d7..c8cce5841 100644 --- a/libraries/libmesosphere/source/kern_k_address_space_info.cpp +++ b/libraries/libmesosphere/source/kern_k_address_space_info.cpp @@ -22,16 +22,16 @@ namespace ams::kern { constexpr uintptr_t Invalid = std::numeric_limits::max(); constexpr KAddressSpaceInfo AddressSpaceInfos[] = { - { .bit_width = 32, .address = 2_MB, .size = 1_GB - 2_MB, .type = KAddressSpaceInfo::Type_32Bit, }, - { .bit_width = 32, .address = 1_GB, .size = 4_GB - 1_GB, .type = KAddressSpaceInfo::Type_Small64Bit, }, + { .bit_width = 32, .address = 2_MB, .size = 1_GB - 2_MB, .type = KAddressSpaceInfo::Type_MapSmall, }, + { .bit_width = 32, .address = 1_GB, .size = 4_GB - 1_GB, .type = KAddressSpaceInfo::Type_MapLarge, }, { .bit_width = 32, .address = Invalid, .size = 1_GB, .type = KAddressSpaceInfo::Type_Heap, }, { .bit_width = 32, .address = Invalid, .size = 1_GB, .type = KAddressSpaceInfo::Type_Alias, }, - { .bit_width = 36, .address = 128_MB, .size = 2_GB - 128_MB, .type = KAddressSpaceInfo::Type_32Bit, }, - { .bit_width = 36, .address = 2_GB, .size = 64_GB - 2_GB, .type = KAddressSpaceInfo::Type_Small64Bit, }, + { .bit_width = 36, .address = 128_MB, .size = 2_GB - 128_MB, .type = KAddressSpaceInfo::Type_MapSmall, }, + { .bit_width = 36, .address = 2_GB, .size = 64_GB - 2_GB, .type = KAddressSpaceInfo::Type_MapLarge, }, { .bit_width = 36, .address = Invalid, .size = 6_GB, .type = KAddressSpaceInfo::Type_Heap, }, { .bit_width = 36, .address = Invalid, .size = 6_GB, .type = KAddressSpaceInfo::Type_Alias, }, - { .bit_width = 39, .address = 128_MB, .size = 512_GB - 128_MB, .type = KAddressSpaceInfo::Type_Large64Bit, }, - { .bit_width = 39, .address = Invalid, .size = 64_GB, .type = KAddressSpaceInfo::Type_32Bit, }, + { .bit_width = 39, .address = 128_MB, .size = 512_GB - 128_MB, .type = KAddressSpaceInfo::Type_Map39Bit, }, + { .bit_width = 39, .address = Invalid, .size = 64_GB, .type = KAddressSpaceInfo::Type_MapSmall, }, { .bit_width = 39, .address = Invalid, .size = 6_GB, .type = KAddressSpaceInfo::Type_Heap, }, { .bit_width = 39, .address = Invalid, .size = 64_GB, .type = KAddressSpaceInfo::Type_Alias, }, { .bit_width = 39, .address = Invalid, .size = 2_GB, .type = KAddressSpaceInfo::Type_Stack, }, @@ -54,15 +54,15 @@ namespace ams::kern { }; constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) { - return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Large64Bit && type != KAddressSpaceInfo::Type_Stack; + return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack; } constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) { - return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Large64Bit && type != KAddressSpaceInfo::Type_Stack; + return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack; } constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) { - return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Small64Bit; + return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_MapLarge; } } diff --git a/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp index f5278d0e1..09a65b769 100644 --- a/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp +++ b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp @@ -106,7 +106,7 @@ namespace ams::kern { const uintptr_t start_address = rx_address; const uintptr_t end_address = bss_size > 0 ? bss_address + bss_size : rw_address + rw_size; const size_t as_width = this->Is64BitAddressSpace() ? 39 : 32; - const ASType as_type = this->Is64BitAddressSpace() ? KAddressSpaceInfo::Type_Large64Bit : KAddressSpaceInfo::Type_32Bit; + const ASType as_type = this->Is64BitAddressSpace() ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall; const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(as_width, as_type); const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(as_width, as_type); const uintptr_t map_end = map_start + map_size; diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index d3529610f..8a79ded60 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -100,9 +100,9 @@ namespace ams::kern { alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias); heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap); stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Stack); - kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_32Bit); - this->code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Large64Bit); - this->code_region_end = this->code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Large64Bit); + kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall); + this->code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Map39Bit); + this->code_region_end = this->code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Map39Bit); this->alias_code_region_start = this->code_region_start; this->alias_code_region_end = this->code_region_end; process_code_start = util::AlignDown(GetInteger(code_address), RegionAlignment); @@ -110,11 +110,11 @@ namespace ams::kern { } else { stack_region_size = 0; kernel_map_region_size = 0; - this->code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_32Bit); - this->code_region_end = this->code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_32Bit); + this->code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_MapSmall); + this->code_region_end = this->code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_MapSmall); this->stack_region_start = this->code_region_start; this->alias_code_region_start = this->code_region_start; - this->alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type_Small64Bit) + GetSpaceSize(KAddressSpaceInfo::Type_Small64Bit); + this->alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type_MapLarge) + GetSpaceSize(KAddressSpaceInfo::Type_MapLarge); this->stack_region_end = this->code_region_end; this->kernel_map_region_start = this->code_region_start; this->kernel_map_region_end = this->code_region_end; diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 66dbea043..3f0791958 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -106,7 +106,7 @@ namespace ams::kern { Result KProcess::Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(res_limit != nullptr); - MESOSPHERE_ABORT_UNLESS((params.code_num_pages * PageSize) / PageSize == params.code_num_pages); + MESOSPHERE_ABORT_UNLESS((params.code_num_pages * PageSize) / PageSize == static_cast(params.code_num_pages)); /* Set members. */ this->memory_pool = pool; @@ -153,6 +153,10 @@ namespace ams::kern { return ResultSuccess(); } + Result KProcess::Initialize(const ams::svc::CreateProcessParameter ¶ms, svc::KUserPointer caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool) { + MESOSPHERE_UNIMPLEMENTED(); + } + void KProcess::DoWorkerTask() { MESOSPHERE_UNIMPLEMENTED(); } diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index dedc57436..0385ceb1e 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -65,6 +65,192 @@ namespace ams::kern::svc { return KProcess::GetProcessList(out_num_processes, out_process_ids, max_out_count); } + Result CreateProcess(ams::svc::Handle *out, const ams::svc::CreateProcessParameter ¶ms, KUserPointer user_caps, int32_t num_caps) { + /* Validate the capabilities pointer. */ + R_UNLESS(num_caps >= 0, svc::ResultInvalidPointer()); + if (num_caps > 0) { + /* Check for overflow. */ + R_UNLESS(((num_caps * sizeof(u32)) / sizeof(u32)) == static_cast(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()); + } + + /* Validate that the parameter flags are valid. */ + R_UNLESS((params.flags & ~ams::svc::CreateProcessFlag_All) == 0, svc::ResultInvalidEnumValue()); + + /* 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)) { + R_UNLESS(!is_64_bit, svc::ResultInvalidCombination()); + } + + /* Decide on an address space map region. */ + uintptr_t map_start, map_end; + size_t map_size; + switch (params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask) { + case ams::svc::CreateProcessFlag_AddressSpace32Bit: + case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias: + { + map_start = KAddressSpaceInfo::GetAddressSpaceStart(32, KAddressSpaceInfo::Type_MapSmall); + map_size = KAddressSpaceInfo::GetAddressSpaceSize(32, KAddressSpaceInfo::Type_MapSmall); + map_end = map_start + map_size; + } + break; + case ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated: + { + /* 64-bit address space requires 64-bit process. */ + R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); + + map_start = KAddressSpaceInfo::GetAddressSpaceStart(36, KAddressSpaceInfo::Type_MapSmall); + map_size = KAddressSpaceInfo::GetAddressSpaceSize(36, KAddressSpaceInfo::Type_MapSmall); + map_end = map_start + map_size; + } + break; + case ams::svc::CreateProcessFlag_AddressSpace64Bit: + { + /* 64-bit address space requires 64-bit process. */ + R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); + + map_start = KAddressSpaceInfo::GetAddressSpaceStart(39, KAddressSpaceInfo::Type_Map39Bit); + map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(39, KAddressSpaceInfo::Type_Map39Bit); + + map_size = KAddressSpaceInfo::GetAddressSpaceSize(39, KAddressSpaceInfo::Type_Heap); + } + break; + default: + return svc::ResultInvalidEnumValue(); + } + + /* 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(); + } + + /* Check that the code address is aligned. */ + R_UNLESS(util::IsAligned(params.code_address, KProcess::AslrAlignment), svc::ResultInvalidAddress()); + + /* Check that the number of code pages is >= 0. */ + R_UNLESS(params.code_num_pages >= 0, svc::ResultInvalidSize()); + + /* Check that the number of extra resource pages is >= 0. */ + R_UNLESS(params.system_resource_num_pages >= 0, svc::ResultInvalidSize()); + + /* Convert to sizes. */ + const size_t code_num_pages = params.code_num_pages; + const size_t system_resource_num_pages = params.system_resource_num_pages; + const size_t total_pages = code_num_pages + system_resource_num_pages; + const size_t code_size = code_num_pages * PageSize; + const size_t system_resource_size = system_resource_num_pages * PageSize; + const size_t total_size = code_size + system_resource_size; + + /* Check for overflow. */ + R_UNLESS((code_size / PageSize) == code_num_pages, svc::ResultInvalidSize()); + R_UNLESS((system_resource_size / PageSize) == system_resource_num_pages, svc::ResultInvalidSize()); + R_UNLESS((code_num_pages + system_resource_num_pages) >= code_num_pages, svc::ResultOutOfMemory()); + R_UNLESS((total_size / PageSize) == total_pages, svc::ResultInvalidSize()); + + /* Check that the number of pages is valid. */ + R_UNLESS(code_num_pages < (map_size / PageSize), svc::ResultInvalidMemoryRegion()); + + /* Validate that the code falls within the map reigon. */ + R_UNLESS(map_start <= params.code_address, svc::ResultInvalidMemoryRegion()); + R_UNLESS(params.code_address < params.code_address + code_size, svc::ResultInvalidMemoryRegion()); + R_UNLESS(params.code_address + code_size - 1 <= map_end - 1, svc::ResultInvalidMemoryRegion()); + + /* Check that the number of pages is valid for the kernel address space. */ + R_UNLESS(code_num_pages < (kern::MainMemorySize / PageSize), svc::ResultOutOfMemory()); + R_UNLESS(system_resource_num_pages < (kern::MainMemorySize / PageSize), svc::ResultOutOfMemory()); + R_UNLESS(total_pages < (kern::MainMemorySize / PageSize), svc::ResultOutOfMemory()); + + /* Check that optimized memory allocation is used only for applications. */ + const bool optimize_allocs = (params.flags & ams::svc::CreateProcessFlag_OptimizeMemoryAllocation) != 0; + const bool is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0; + R_UNLESS(!optimize_allocs || is_application, svc::ResultBusy()); + + /* Get the current handle table. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + + /* Create the new process. */ + KProcess *process = KProcess::Create(); + R_UNLESS(process != nullptr, svc::ResultOutOfResource()); + + /* Ensure that the only reference to the process is in the handle table when we're done. */ + ON_SCOPE_EXIT { process->Close(); }; + + /* Get the resource limit from the handle. */ + KScopedAutoObject resource_limit = handle_table.GetObject(params.reslimit); + R_UNLESS(resource_limit.IsNotNull() || params.reslimit == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); + + /* Decide on a resource limit for the process. */ + 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; + } + + /* Initialize the process. */ + R_TRY(process->Initialize(params, user_caps, num_caps, process_resource_limit, pool)); + + /* Register the process. */ + R_TRY(KProcess::Register(process)); + + /* Add the process to the handle table. */ + R_TRY(handle_table.Add(out, process)); + + return ResultSuccess(); + } + + template + Result CreateProcess(ams::svc::Handle *out, KUserPointer user_parameters, KUserPointer user_caps, int32_t num_caps) { + /* Read the parameters from user space. */ + T params; + R_TRY(user_parameters.CopyTo(std::addressof(params))); + + /* Invoke the implementation. */ + if constexpr (std::same_as) { + return CreateProcess(out, params, user_caps, num_caps); + } else { + /* Convert the parameters. */ + ams::svc::CreateProcessParameter converted_params; + static_assert(sizeof(T{}.name) == sizeof(ams::svc::CreateProcessParameter{}.name)); + + std::memcpy(converted_params.name, params.name, sizeof(converted_params.name)); + converted_params.version = params.version; + converted_params.program_id = params.program_id; + converted_params.code_address = params.code_address; + converted_params.code_num_pages = params.code_num_pages; + converted_params.flags = params.flags; + converted_params.reslimit = params.reslimit; + converted_params.system_resource_num_pages = params.system_resource_num_pages; + + /* Invoke. */ + return CreateProcess(out, converted_params, user_caps, num_caps); + } + } + } /* ============================= 64 ABI ============================= */ @@ -82,7 +268,7 @@ namespace ams::kern::svc { } Result CreateProcess64(ams::svc::Handle *out_handle, KUserPointer parameters, KUserPointer caps, int32_t num_caps) { - MESOSPHERE_PANIC("Stubbed SvcCreateProcess64 was called."); + return CreateProcess(out_handle, parameters, caps, num_caps); } Result StartProcess64(ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) { @@ -112,7 +298,7 @@ namespace ams::kern::svc { } Result CreateProcess64From32(ams::svc::Handle *out_handle, KUserPointer parameters, KUserPointer caps, int32_t num_caps) { - MESOSPHERE_PANIC("Stubbed SvcCreateProcess64From32 was called."); + return CreateProcess(out_handle, parameters, caps, num_caps); } Result StartProcess64From32(ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) { diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index bf4530a64..70e3bf78f 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -374,6 +374,15 @@ namespace ams::svc { /* 7.x+ Should memory allocation be optimized? This requires IsApplication. */ CreateProcessFlag_OptimizeMemoryAllocation = (1 << 11), + + /* Mask of all flags. */ + CreateProcessFlag_All = CreateProcessFlag_Is64Bit | + CreateProcessFlag_AddressSpaceMask | + CreateProcessFlag_EnableDebug | + CreateProcessFlag_EnableAslr | + CreateProcessFlag_IsApplication | + CreateProcessFlag_PoolPartitionMask | + CreateProcessFlag_OptimizeMemoryAllocation, }; /* Debug types. */ diff --git a/libraries/libvapours/include/vapours/svc/svc_types_priv.hpp b/libraries/libvapours/include/vapours/svc/svc_types_priv.hpp index f6da8637b..3e2e11758 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_priv.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_priv.hpp @@ -25,10 +25,10 @@ namespace ams::svc { u32 version; u64 program_id; u64 code_address; - u32 code_num_pages; + s32 code_num_pages; u32 flags; Handle reslimit; - u32 system_resource_num_pages; + s32 system_resource_num_pages; }; static_assert(sizeof(CreateProcessParameter) == 0x30); @@ -41,10 +41,10 @@ namespace ams::svc { u32 version; u64 program_id; u64 code_address; - u32 code_num_pages; + s32 code_num_pages; u32 flags; Handle reslimit; - u32 system_resource_num_pages; + s32 system_resource_num_pages; }; static_assert(sizeof(CreateProcessParameter) == 0x30);