From cbc73f44077b5527b2e211b7cb2a9f42b6e89801 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 15 Feb 2020 03:44:41 -0800 Subject: [PATCH] kern: skeleton initial process loading --- .../mesosphere/kern_initial_process.hpp | 2 + .../mesosphere/kern_k_address_space_info.hpp | 51 +++++++ .../kern_k_initial_process_reader.hpp | 132 ++++++++++++++++++ .../source/kern_initial_process.cpp | 87 ++++++++++++ .../source/kern_k_address_space_info.cpp | 103 ++++++++++++++ .../source/kern_k_initial_process_reader.cpp | 88 ++++++++++++ libraries/libmesosphere/source/kern_main.cpp | 3 +- 7 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp create mode 100644 libraries/libmesosphere/include/mesosphere/kern_k_initial_process_reader.hpp create mode 100644 libraries/libmesosphere/source/kern_k_address_space_info.cpp create mode 100644 libraries/libmesosphere/source/kern_k_initial_process_reader.cpp diff --git a/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp index 8b762e254..e5e6c2f40 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include namespace ams::kern { @@ -29,6 +30,7 @@ namespace ams::kern { }; NOINLINE void CopyInitialProcessBinaryToKernelMemory(); + NOINLINE void CreateAndRunInitialProcesses(); u64 GetInitialProcessIdMin(); u64 GetInitialProcessIdMax(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp new file mode 100644 index 000000000..0457381f6 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +namespace ams::kern { + + + + struct KAddressSpaceInfo { + public: + enum Type { + Type_32Bit = 0, + Type_Small64Bit = 1, + Type_Large64Bit = 2, + Type_Heap = 3, + Type_Stack = 4, + Type_Alias = 5, + + Type_Count, + }; + private: + size_t bit_width; + size_t address; + size_t size; + Type type; + public: + static uintptr_t GetAddressSpaceStart(size_t width, Type type); + static size_t GetAddressSpaceSize(size_t width, Type type); + + constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : bit_width(bw), address(a), size(s), type(t) { /* ... */ } + + constexpr size_t GetWidth() const { return this->bit_width; } + constexpr size_t GetAddress() const { return this->address; } + constexpr size_t GetSize() const { return this->size; } + constexpr Type GetType() const { return this->type; } + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_initial_process_reader.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_initial_process_reader.hpp new file mode 100644 index 000000000..d70ade490 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_initial_process_reader.hpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::kern { + + class KInitialProcessHeader { + private: + static constexpr u32 Magic = util::FourCC<'K','I','P','1'>::Code; + private: + u32 magic; + u8 name[12]; + u64 program_id; + u32 version; + u8 priority; + u8 ideal_core_id; + u8 _1E; + u8 flags; + u32 rx_address; + u32 rx_size; + u32 rx_compressed_size; + u32 affinity_mask; + u32 ro_address; + u32 ro_size; + u32 ro_compressed_size; + u32 stack_size; + u32 rw_address; + u32 rw_size; + u32 rw_compressed_size; + u32 _4C; + u32 bss_address; + u32 bss_size; + u32 pad[(0x80 - 0x58) / sizeof(u32)]; + u32 capabilities[0x80 / sizeof(u32)]; + public: + constexpr bool IsValid() const { return this->magic == Magic; } + + constexpr void GetName(char *dst, size_t size) const { + std::memset(dst, 0, size); + std::memcpy(dst, this->name, std::min(sizeof(this->name), size)); + } + + constexpr const u32 *GetCapabilities() const { return this->capabilities; } + constexpr size_t GetNumCapabilities() const { return util::size(this->capabilities); } + + constexpr u64 GetProgramId() const { return this->program_id; } + constexpr u32 GetVersion() const { return this->version; } + constexpr u8 GetPriority() const { return this->priority; } + constexpr u8 GetIdealCore() const { return this->ideal_core_id; } + + constexpr bool IsRxCompressed() const { return (this->flags & (1 << 0)); } + constexpr bool IsRoCompressed() const { return (this->flags & (1 << 1)); } + constexpr bool IsRwCompressed() const { return (this->flags & (1 << 2)); } + constexpr bool Is64Bit() const { return (this->flags & (1 << 3)); } + constexpr bool Is64BitAddressSpace() const { return (this->flags & (1 << 4)); } + constexpr bool UsesSecureMemory() const { return (this->flags & (1 << 5)); } + + constexpr u32 GetRxAddress() const { return this->rx_address; } + constexpr u32 GetRxSize() const { return this->rx_size; } + constexpr u32 GetRxCompressedSize() const { return this->rx_compressed_size; } + constexpr u32 GetRoAddress() const { return this->ro_address; } + constexpr u32 GetRoSize() const { return this->ro_size; } + constexpr u32 GetRoCompressedSize() const { return this->ro_compressed_size; } + constexpr u32 GetRwAddress() const { return this->rw_address; } + constexpr u32 GetRwSize() const { return this->rw_size; } + constexpr u32 GetRwCompressedSize() const { return this->rw_compressed_size; } + constexpr u32 GetBssAddress() const { return this->bss_address; } + constexpr u32 GetBssSize() const { return this->bss_size; } + + constexpr u32 GetAffinityMask() const { return this->affinity_mask; } + constexpr u32 GetStackSize() const { return this->stack_size; } + }; + static_assert(sizeof(KInitialProcessHeader) == 0x100); + + class KInitialProcessReader { + private: + KInitialProcessHeader *kip_header; + public: + constexpr KInitialProcessReader() : kip_header() { /* ... */ } + + constexpr const u32 *GetCapabilities() const { return this->kip_header->GetCapabilities(); } + constexpr size_t GetNumCapabilities() const { return this->kip_header->GetNumCapabilities(); } + + constexpr size_t GetBinarySize() const { + return sizeof(*kip_header) + this->kip_header->GetRxCompressedSize() + this->kip_header->GetRoCompressedSize() + this->kip_header->GetRwCompressedSize(); + } + + constexpr size_t GetSize() const { + if (const size_t bss_size = this->kip_header->GetBssSize(); bss_size != 0) { + return this->kip_header->GetBssAddress() + this->kip_header->GetBssSize(); + } else { + return this->kip_header->GetRwAddress() + this->kip_header->GetRwSize(); + } + } + + constexpr u8 GetPriority() const { return this->kip_header->GetPriority(); } + constexpr u8 GetIdealCore() const { return this->kip_header->GetIdealCore(); } + constexpr u32 GetAffinityMask() const { return this->kip_header->GetAffinityMask(); } + constexpr u32 GetStackSize() const { return this->kip_header->GetStackSize(); } + + constexpr bool Is64Bit() const { return this->kip_header->Is64Bit(); } + constexpr bool Is64BitAddressSpace() const { return this->kip_header->Is64BitAddressSpace(); } + constexpr bool UsesSecureMemory() const { return this->kip_header->UsesSecureMemory(); } + + bool Attach(u8 *bin) { + if (KInitialProcessHeader *header = reinterpret_cast(bin); header->IsValid()) { + this->kip_header = header; + return true; + } else { + return false; + } + } + + Result MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const; + }; + +} diff --git a/libraries/libmesosphere/source/kern_initial_process.cpp b/libraries/libmesosphere/source/kern_initial_process.cpp index 882c068bf..54e2b7965 100644 --- a/libraries/libmesosphere/source/kern_initial_process.cpp +++ b/libraries/libmesosphere/source/kern_initial_process.cpp @@ -19,6 +19,12 @@ namespace ams::kern { namespace { + struct InitialProcessInfo { + KProcess *process; + size_t stack_size; + s32 priority; + }; + KVirtualAddress GetInitialProcessBinaryAddress() { return KMemoryLayout::GetPageTableHeapRegion().GetEndAddress() - InitialProcessBinarySizeMax; } @@ -32,6 +38,59 @@ namespace ams::kern { MESOSPHERE_ABORT_UNLESS(header->num_processes <= init::GetSlabResourceCounts().num_KProcess); } + 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)); + + 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)); + + /* Parse process parameters and reserve memory. */ + ams::svc::CreateProcessParameter params; + MESOSPHERE_R_ABORT_UNLESS(reader.MakeCreateProcessParameter(std::addressof(params), true)); + MESOSPHERE_TODO("Reserve memory"); + + /* Create the process, and ensure we don't leak pages. */ + { + /* Allocate memory for the process. */ + MESOSPHERE_TODO("Allocate memory for the process"); + + /* Map the process's memory into the temporary region. */ + MESOSPHERE_TODO("Map the process's page group"); + + /* Load the process. */ + MESOSPHERE_TODO("Load the process"); + + /* Unmap the temporary mapping. */ + MESOSPHERE_TODO("Unmap the process's page group"); + + /* Create a KProcess object. */ + MESOSPHERE_TODO("Create a KProcess"); + + /* Initialize the process. */ + MESOSPHERE_TODO("Initialize the process"); + } + + /* Set the process's memory permissions. */ + MESOSPHERE_TODO("Set process's memory permissions"); + + /* Register the process. */ + MESOSPHERE_TODO("Register the process"); + + /* Save the process info. */ + infos[i].process = /* TODO */ nullptr; + infos[i].stack_size = reader.GetStackSize(); + infos[i].priority = reader.GetPriority(); + + /* Advance the reader. */ + current += reader.GetBinarySize(); + } + } + KVirtualAddress g_initial_process_binary_address; InitialProcessBinaryHeader g_initial_process_binary_header; u64 g_initial_process_id_min = std::numeric_limits::max(); @@ -71,4 +130,32 @@ namespace ams::kern { } } + void CreateAndRunInitialProcesses() { + /* Allocate space for the processes. */ + InitialProcessInfo *infos = static_cast(__builtin_alloca(sizeof(InitialProcessInfo) * g_initial_process_binary_header.num_processes)); + + /* Create the processes. */ + CreateProcesses(infos, g_initial_process_binary_address, g_initial_process_binary_header); + + /* Release the memory used by the image. */ + { + const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize); + const size_t num_pages = total_size / PageSize; + Kernel::GetMemoryManager().Close(g_initial_process_binary_address, num_pages); + Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, total_size); + } + + /* Determine the initial process id range. */ + for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) { + const auto pid = infos[i].process->GetId(); + g_initial_process_id_min = std::min(g_initial_process_id_min, pid); + g_initial_process_id_max = std::max(g_initial_process_id_max, pid); + } + + /* Run the processes. */ + for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) { + MESOSPHERE_TODO("infos[i].process->Run(infos[i].priority, infos[i].stack_size);"); + } + } + } diff --git a/libraries/libmesosphere/source/kern_k_address_space_info.cpp b/libraries/libmesosphere/source/kern_k_address_space_info.cpp new file mode 100644 index 000000000..e8c04ec91 --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_address_space_info.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::kern { + + namespace { + + constexpr uintptr_t Invalid = std::numeric_limits::max(); + + constexpr KAddressSpaceInfo AddressSpaceInfos[] = { + { .bit_width = 32, .address = 2_MB, .size = 1_GB - 2_MB, KAddressSpaceInfo::Type_32Bit, }, + { .bit_width = 32, .address = 1_GB, .size = 4_GB - 1_GB, KAddressSpaceInfo::Type_Small64Bit, }, + { .bit_width = 32, .address = Invalid, .size = 1_GB, KAddressSpaceInfo::Type_Heap, }, + { .bit_width = 32, .address = Invalid, .size = 1_GB, KAddressSpaceInfo::Type_Alias, }, + { .bit_width = 36, .address = 128_MB, .size = 2_GB - 128_MB, KAddressSpaceInfo::Type_32Bit, }, + { .bit_width = 36, .address = 2_GB, .size = 64_GB - 2_GB, KAddressSpaceInfo::Type_Small64Bit, }, + { .bit_width = 36, .address = Invalid, .size = 6_GB, KAddressSpaceInfo::Type_Heap, }, + { .bit_width = 36, .address = Invalid, .size = 6_GB, KAddressSpaceInfo::Type_Alias, }, + { .bit_width = 39, .address = 128_MB, .size = 512_GB - 128_MB, KAddressSpaceInfo::Type_Large64Bit, }, + { .bit_width = 39, .address = Invalid, .size = 64_GB, KAddressSpaceInfo::Type_32Bit, }, + { .bit_width = 39, .address = Invalid, .size = 6_GB, KAddressSpaceInfo::Type_Heap, }, + { .bit_width = 39, .address = Invalid, .size = 64_GB, KAddressSpaceInfo::Type_Alias, }, + { .bit_width = 39, .address = Invalid, .size = 2_GB, KAddressSpaceInfo::Type_Stack, }, + }; + + constexpr bool IsAllowedIndexForAddress(size_t index) { + return index < util::size(AddressSpaceInfos) && AddressSpaceInfos[index].GetAddress() != Invalid; + } + + constexpr size_t AddressSpaceIndices32Bit[KAddressSpaceInfo::Type_Count] = { + 0, 1, 0, 2, 0, 3, + }; + + constexpr size_t AddressSpaceIndices36Bit[KAddressSpaceInfo::Type_Count] = { + 4, 5, 4, 6, 4, 7, + }; + + constexpr size_t AddressSpaceIndices39Bit[KAddressSpaceInfo::Type_Count] = { + 9, 8, 8, 10, 12, 11, + }; + + constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) { + return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Large64Bit && type != KAddressSpaceInfo::Type_Stack; + } + + constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) { + return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Large64Bit && type != KAddressSpaceInfo::Type_Stack; + } + + constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) { + return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Small64Bit; + } + + } + + uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) { + switch (width) { + case 32: + MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type)); + MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[type])); + return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetAddress(); + case 36: + MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type)); + MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[type])); + return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetAddress(); + case 39: + MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type)); + MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[type])); + return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetAddress(); + MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); + } + } + + size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) { + switch (width) { + case 32: + MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type)); + return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetSize(); + case 36: + MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type)); + return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetSize(); + case 39: + MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type)); + return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetSize(); + MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); + } + } + +} diff --git a/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp new file mode 100644 index 000000000..6be4b9629 --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::kern { + + Result KInitialProcessReader::MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const { + /* Get and validate addresses/sizes. */ + const uintptr_t rx_address = this->kip_header->GetRxAddress(); + const size_t rx_size = this->kip_header->GetRxSize(); + const uintptr_t ro_address = this->kip_header->GetRoAddress(); + const size_t ro_size = this->kip_header->GetRoSize(); + const uintptr_t rw_address = this->kip_header->GetRwAddress(); + const size_t rw_size = this->kip_header->GetRwSize(); + const uintptr_t bss_address = this->kip_header->GetBssAddress(); + const size_t bss_size = this->kip_header->GetBssSize(); + R_UNLESS(util::IsAligned(rx_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(ro_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(rw_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(rx_address <= rx_address + util::AlignUp(rx_size, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(ro_address <= ro_address + util::AlignUp(ro_size, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(rw_address <= rw_address + util::AlignUp(rw_size, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(bss_address <= bss_address + util::AlignUp(bss_size, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(rx_address + util::AlignUp(rx_size, PageSize) <= ro_address, svc::ResultInvalidAddress()); + R_UNLESS(ro_address + util::AlignUp(ro_size, PageSize) <= rw_address, svc::ResultInvalidAddress()); + R_UNLESS(rw_address + rw_size <= bss_address, svc::ResultInvalidAddress()); + + /* Validate the address space. */ + if (this->Is64BitAddressSpace()) { + R_UNLESS(this->Is64Bit(), svc::ResultInvalidCombination()); + } + + using ASType = KAddressSpaceInfo::Type; + + 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 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; + MESOSPHERE_ABORT_UNLESS(start_address == 0); + + /* Set fields in parameter. */ + out->code_address = map_start + start_address; + out->code_num_pages = util::AlignUp(end_address - start_address, PageSize); + out->program_id = this->kip_header->GetProgramId(); + out->version = this->kip_header->GetVersion(); + out->flags = 0; + MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize)); + + /* Copy name field. */ + this->kip_header->GetName(out->name, sizeof(out->name)); + + /* Apply ASLR, if needed. */ + if (enable_aslr) { + const size_t choices = (map_end / KernelAslrAlignment) - (util::AlignUp(out->code_address + out->code_num_pages * PageSize, KernelAslrAlignment) / KernelAslrAlignment); + out->code_address += KSystemControl::GenerateRandomRange(0, choices) * KernelAslrAlignment; + out->flags |= ams::svc::CreateProcessFlag_EnableAslr; + } + + /* Apply other flags. */ + if (this->Is64Bit()) { + out->flags |= ams::svc::CreateProcessFlag_Is64Bit; + } + if (this->Is64BitAddressSpace()) { + out->flags |= ams::svc::CreateProcessFlag_AddressSpace64Bit; + } else { + out->flags |= ams::svc::CreateProcessFlag_AddressSpace32Bit; + } + + return ResultSuccess(); + } + +} diff --git a/libraries/libmesosphere/source/kern_main.cpp b/libraries/libmesosphere/source/kern_main.cpp index 3209e3129..762a841e2 100644 --- a/libraries/libmesosphere/source/kern_main.cpp +++ b/libraries/libmesosphere/source/kern_main.cpp @@ -116,7 +116,8 @@ namespace ams::kern { /* Initialize the SMMU. */ KDeviceAddressSpace::Initialize(); - MESOSPHERE_TODO("CreateAndRunInitialProcesses();"); + /* Load the initial processes. */ + CreateAndRunInitialProcesses(); /* We're done initializing! */ Kernel::SetState(Kernel::State::Initialized);