kern: fix initial process binary load on 2.0.0-4.1.0 (closes #1460)

This commit is contained in:
Michael Scire 2021-04-21 19:24:41 -07:00
parent ed80d6ec8c
commit 19be54ff95
6 changed files with 40 additions and 12 deletions

View file

@ -37,4 +37,6 @@ namespace ams::kern {
KVirtualAddress GetInitialProcessBinaryAddress();
size_t GetInitialProcessesSecureMemorySize();
void LoadInitialProcessBinaryHeaderDeprecated(KPhysicalAddress pool_end);
}

View file

@ -175,7 +175,14 @@ namespace ams::kern {
return std::make_tuple(total_size, kernel_size);
}
static void InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start);
static void InitializeLinearMemoryAddresses(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start) {
/* Set static differences. */
s_linear_phys_to_virt_diff = GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
s_linear_virt_to_phys_diff = GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
}
static void InitializeLinearMemoryRegionTrees();
static size_t GetResourceRegionSizeForInit();
static NOINLINE auto GetKernelRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel); }

View file

@ -31,10 +31,12 @@ namespace ams::kern {
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
constinit u64 g_initial_process_id_max = std::numeric_limits<u64>::min();
void LoadInitialProcessBinaryHeader() {
void LoadInitialProcessBinaryHeader(KVirtualAddress virt_addr = Null<KVirtualAddress>) {
if (g_initial_process_binary_header.magic != InitialProcessBinaryMagic) {
/* Get the virtual address for the image. */
const KVirtualAddress virt_addr = GetInitialProcessBinaryAddress();
/* Get the virtual address, if it's not overridden. */
if (virt_addr == Null<KVirtualAddress>) {
virt_addr = GetInitialProcessBinaryAddress();
}
/* Copy and validate the header. */
g_initial_process_binary_header = *GetPointer<InitialProcessBinaryHeader>(virt_addr);
@ -54,12 +56,16 @@ namespace ams::kern {
/* Attach to the current KIP. */
KInitialProcessReader reader;
MESOSPHERE_ABORT_UNLESS(reader.Attach(current) != Null<KVirtualAddress>);
KVirtualAddress data = reader.Attach(current);
MESOSPHERE_ABORT_UNLESS(data != Null<KVirtualAddress>);
/* If the process uses secure memory, account for that. */
if (reader.UsesSecureMemory()) {
g_initial_process_secure_memory_size += reader.GetSize() + util::AlignUp(reader.GetStackSize(), PageSize);
}
/* Advance to the next KIP. */
current = data + reader.GetBinarySize();
}
}
}
@ -267,6 +273,10 @@ namespace ams::kern {
}
}
ALWAYS_INLINE KVirtualAddress GetInitialProcessBinaryAddress(KVirtualAddress pool_end) {
return pool_end - InitialProcessBinarySizeMax;
}
}
u64 GetInitialProcessIdMin() {
@ -283,7 +293,7 @@ namespace ams::kern {
MESOSPHERE_INIT_ABORT_UNLESS(pool_region != nullptr);
MESOSPHERE_INIT_ABORT_UNLESS(pool_region->GetEndAddress() != 0);
MESOSPHERE_ABORT_UNLESS(pool_region->GetSize() >= InitialProcessBinarySizeMax);
return pool_region->GetEndAddress() - InitialProcessBinarySizeMax;
return GetInitialProcessBinaryAddress(pool_region->GetEndAddress());
}
size_t GetInitialProcessesSecureMemorySize() {
@ -311,6 +321,10 @@ namespace ams::kern {
}
}
void LoadInitialProcessBinaryHeaderDeprecated(KPhysicalAddress pool_end) {
LoadInitialProcessBinaryHeader(GetInitialProcessBinaryAddress(KMemoryLayout::GetLinearVirtualAddress(pool_end)));
}
void CreateAndRunInitialProcesses() {
/* Allocate space for the processes. */
InitialProcessInfo *infos = static_cast<InitialProcessInfo *>(__builtin_alloca(sizeof(InitialProcessInfo) * g_initial_process_binary_header.num_processes));

View file

@ -185,6 +185,12 @@ namespace ams::kern {
static_assert(KMemoryManager::Pool_Unsafe == KMemoryManager::Pool_Application);
static_assert(KMemoryManager::Pool_Secure == KMemoryManager::Pool_System);
/* NOTE: Beginning with 12.0.0 (and always, in mesosphere), the initial process binary is at the end of the pool region. */
/* However, this is problematic for < 5.0.0, because we require the initial process binary to be parsed in order */
/* to determine the pool sizes. Hence, we will force an initial binary load with the known pool end directly, so */
/* that we retain compatibility with lower firmware versions. */
LoadInitialProcessBinaryHeaderDeprecated(pool_end);
/* Get Secure pool size. */
const size_t secure_pool_size = [] ALWAYS_INLINE_LAMBDA (auto target_firmware) -> size_t {
constexpr size_t LegacySecureKernelSize = 8_MB; /* KPageBuffer pages, other small kernel allocations. */

View file

@ -148,11 +148,7 @@ namespace ams::kern {
}
}
void KMemoryLayout::InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start) {
/* Set static differences. */
s_linear_phys_to_virt_diff = GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
s_linear_virt_to_phys_diff = GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
void KMemoryLayout::InitializeLinearMemoryRegionTrees() {
/* Initialize linear trees. */
for (auto &region : GetPhysicalMemoryRegionTree()) {
if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {

View file

@ -467,11 +467,14 @@ namespace ams::kern::init {
}
}
/* Set the linear memory offsets, to enable conversion between physical and virtual addresses. */
KMemoryLayout::InitializeLinearMemoryAddresses(aligned_linear_phys_start, linear_region_start);
/* Setup all other memory regions needed to arrange the pool partitions. */
SetupPoolPartitionMemoryRegions();
/* Cache all linear regions in their own trees for faster access, later. */
KMemoryLayout::InitializeLinearMemoryRegionTrees(aligned_linear_phys_start, linear_region_start);
KMemoryLayout::InitializeLinearMemoryRegionTrees();
/* Turn on all other cores. */
TurnOnAllCores(GetInteger(init_pt.GetPhysicalAddress(reinterpret_cast<uintptr_t>(::ams::kern::init::StartOtherCore))));