diff --git a/stratosphere/loader/source/ldr_npdm.cpp b/stratosphere/loader/source/ldr_npdm.cpp index 231f4b9ba..03f5f23d4 100644 --- a/stratosphere/loader/source/ldr_npdm.cpp +++ b/stratosphere/loader/source/ldr_npdm.cpp @@ -377,3 +377,22 @@ Result NpdmUtils::ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 return rc; } + +u32 NpdmUtils::GetApplicationType(u32 *caps, size_t num_caps) { + u32 application_type = 0; + for (unsigned int i = 0; i < num_caps; i++) { + if ((caps[i] & 0x3FFF) == 0x1FFF) { + u16 app_type = (caps[i] >> 14) & 7; + if (app_type == 1) { + application_type |= 1; + } else if (app_type == 2) { + application_type |= 2; + } + } + /* After 1.0.0, allow_debug is used as bit 4. */ + if (kernelAbove200() && (caps[i] & 0x1FFFF) == 0xFFFF) { + application_type |= (caps[i] >> 15) & 4; + } + } + return application_type; +} \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_npdm.hpp b/stratosphere/loader/source/ldr_npdm.hpp index 201741b00..a2825804c 100644 --- a/stratosphere/loader/source/ldr_npdm.hpp +++ b/stratosphere/loader/source/ldr_npdm.hpp @@ -17,7 +17,8 @@ class NpdmUtils { u8 _0xD; u8 main_thread_prio; u8 default_cpuid; - u64 _0x10; + u32 _0x10; + u32 system_resource_size; u32 process_category; u32 main_stack_size; char title_name[0x50]; @@ -77,6 +78,8 @@ class NpdmUtils { static_assert(sizeof(NpdmAcid) == 0x240, "Incorrectly defined NpdmAcid!"); static_assert(sizeof(NpdmAci0) == 0x40, "Incorrectly defined NpdmAci0!"); + static u32 GetApplicationType(u32 *caps, size_t num_caps); + static Result ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining); static Result ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps); diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 87f3f2c9f..53f720590 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -1,4 +1,5 @@ #include +#include #include "ldr_process_creation.hpp" #include "ldr_registration.hpp" @@ -7,8 +8,87 @@ #include "ldr_npdm.hpp" #include "ldr_nso.hpp" -Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 flags, Handle reslimit_h) { - NpdmUtils::NpdmInfo info; +Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info) { + /* Initialize a ProcessInfo using an npdm. */ + *out_proc_info = (const ProcessCreation::ProcessInfo){0}; + + /* Copy all but last char of name, insert NULL terminator. */ + std::copy(npdm->header->title_name, npdm->header->title_name + sizeof(out_proc_info->name) - 1, out_proc_info->name); + out_proc_info->name[sizeof(out_proc_info->name) - 1] = 0; + + /* Set title id. */ + out_proc_info->title_id = npdm->aci0->title_id; + + /* Set process category. */ + out_proc_info->process_category = npdm->header->process_category; + + /* Copy reslimit handle raw. */ + out_proc_info->reslimit_h = reslimit_h; + + /* Set IsAddressSpace64Bit, AddressSpaceType. */ + if (npdm->header->mmu_flags & 8) { + /* Invalid Address Space Type. */ + return 0x809; + } + out_proc_info->process_flags = (npdm->header->mmu_flags & 0xF); + /* Set Bit 4 (?) and EnableAslr based on argument flags. */ + out_proc_info->process_flags |= ((arg_flags & 3) << 4) ^ 0x20; + /* Set UseSystemMemBlocks if application type is 1. */ + u32 application_type = NpdmUtils::GetApplicationType((u32 *)npdm->aci0_kac, npdm->aci0->kac_size / sizeof(u32)); + if ((application_type & 3) == 1) { + out_proc_info->process_flags |= 0x40; + } + + /* 3.0.0+ System Resource Size. */ + if (kernelAbove300()) { + if (npdm->header->system_resource_size & 0x1FFFFF) { + return 0xA409; + } + if (npdm->header->system_resource_size) { + if ((out_proc_info->process_flags & 6) == 0) { + return 0x809; + } + if ((application_type & 3) != 1) { + return 0x809; + } + if (npdm->header->system_resource_size > 0x1FE00000) { + return 0x809; + } + } + out_proc_info->system_resource_num_pages = npdm->header->system_resource_size >> 12; + } else { + out_proc_info->system_resource_num_pages = 0; + } + + /* 5.0.0+ Pool Partition. */ + if (kernelAbove500()) { + u32 pool_partition_id = (npdm->acid->is_retail >> 2) & 0xF; + switch (pool_partition_id) { + case 0: /* Application. */ + if ((application_type & 3) == 2) { + out_proc_info->process_flags |= 0x80; + } + break; + case 1: /* Applet. */ + out_proc_info->process_flags |= 0x80; + break; + case 2: /* Sysmodule. */ + out_proc_info->process_flags |= 0x100; + break; + case 3: /* nvservices. */ + out_proc_info->process_flags |= 0x180; + break; + default: + return 0x809; + } + } + + return 0x0; +} + +Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 arg_flags, Handle reslimit_h) { + NpdmUtils::NpdmInfo npdm_info = {0}; + ProcessInfo process_info = {0}; Registration::Process *target_process; Result rc; @@ -25,25 +105,25 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc } /* Load the process's NPDM. */ - rc = NpdmUtils::LoadNpdmFromCache(target_process->tid_sid.title_id, &info); + rc = NpdmUtils::LoadNpdmFromCache(target_process->tid_sid.title_id, &npdm_info); if (R_FAILED(rc)) { goto CREATE_PROCESS_END; } /* Validate the title we're loading is what we expect. */ - if (info.aci0->title_id < info.acid->title_id_range_min || info.aci0->title_id > info.acid->title_id_range_max) { + if (npdm_info.aci0->title_id < npdm_info.acid->title_id_range_min || npdm_info.aci0->title_id > npdm_info.acid->title_id_range_max) { rc = 0x1209; goto CREATE_PROCESS_END; } /* Validate that the ACI0 Kernel Capabilities are valid and restricted by the ACID Kernel Capabilities. */ - rc = NpdmUtils::ValidateCapabilities((u32 *)info.acid_kac, info.acid->kac_size/sizeof(u32), (u32 *)info.aci0_kac, info.aci0->kac_size/sizeof(u32)); + rc = NpdmUtils::ValidateCapabilities((u32 *)npdm_info.acid_kac, npdm_info.acid->kac_size/sizeof(u32), (u32 *)npdm_info.aci0_kac, npdm_info.aci0->kac_size/sizeof(u32)); if (R_FAILED(rc)) { goto CREATE_PROCESS_END; } /* Read in all NSO headers, see what NSOs are present. */ - rc = NsoUtils::LoadNsoHeaders(info.aci0->title_id); + rc = NsoUtils::LoadNsoHeaders(npdm_info.aci0->title_id); if (R_FAILED(rc)) { goto CREATE_PROCESS_END; } @@ -54,7 +134,11 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc goto CREATE_PROCESS_END; } - /* TODO: Create the CreateProcessInfo. */ + /* Initialize the ProcessInfo. */ + rc = ProcessCreation::InitializeProcessInfo(&npdm_info, reslimit_h, arg_flags, &process_info); + if (R_FAILED(rc)) { + goto CREATE_PROCESS_END; + } /* TODO: Figure out where NSOs will be mapped, and how much space they (and arguments) will take up. */ diff --git a/stratosphere/loader/source/ldr_process_creation.hpp b/stratosphere/loader/source/ldr_process_creation.hpp index 778de83e0..6b87e005d 100644 --- a/stratosphere/loader/source/ldr_process_creation.hpp +++ b/stratosphere/loader/source/ldr_process_creation.hpp @@ -3,10 +3,22 @@ #include "ldr_registration.hpp" #include "ldr_launch_queue.hpp" +#include "ldr_npdm.hpp" /* Utilities for Process Creation, for Loader. */ class ProcessCreation { public: - static Result CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 flags, Handle reslimit_h); + struct ProcessInfo { + u8 name[12]; + u32 process_category; + u64 title_id; + u64 code_addr; + u32 code_num_pages; + u32 process_flags; + Handle reslimit_h; + u32 system_resource_num_pages; + }; + static Result InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info); + static Result CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 arg_flags, Handle reslimit_h); }; \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_process_manager.cpp b/stratosphere/loader/source/ldr_process_manager.cpp index b39861d37..98ee6f0a2 100644 --- a/stratosphere/loader/source/ldr_process_manager.cpp +++ b/stratosphere/loader/source/ldr_process_manager.cpp @@ -152,19 +152,7 @@ Result ProcessManagerService::populate_program_info_buffer(ProcessManagerService /* Parse application type. */ if (R_SUCCEEDED(rc)) { - u32 *kac = (u32 *)info.acid_kac; - u32 num_entries = info.acid->kac_size / sizeof(u32); - out->application_type = 0; - for (unsigned int i = 0; i < num_entries; i++) { - if ((kac[i] & 0x3FFF) == 0x1FFF) { - u16 app_type = (kac[i] >> 14) & 7; - if (app_type == 1) { - out->application_type |= 1; - } else if (app_type == 2) { - out->application_type |= 2; - } - } - } + out->application_type = NpdmUtils::GetApplicationType((u32 *)info.acid_kac, info.acid->kac_size / sizeof(u32)); }