kern: skeleton initial process loading
This commit is contained in:
@@ -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<u8>(binary_address + sizeof(InitialProcessBinaryHeader));
|
||||
const u8 * const end = GetPointer<u8>(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<u64>::max();
|
||||
@@ -71,4 +130,32 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
void CreateAndRunInitialProcesses() {
|
||||
/* Allocate space for the processes. */
|
||||
InitialProcessInfo *infos = static_cast<InitialProcessInfo *>(__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);");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
103
libraries/libmesosphere/source/kern_k_address_space_info.cpp
Normal file
103
libraries/libmesosphere/source/kern_k_address_space_info.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user