kern: pass ini1 size from loader to kernel, remove slab memset from init0

This commit is contained in:
Michael Scire 2023-10-11 02:02:49 -07:00 committed by SciresM
parent add4b3fdc3
commit 4ca3c44e5f
6 changed files with 62 additions and 31 deletions

View file

@ -34,8 +34,14 @@ namespace ams::kern {
uintptr_t _08; uintptr_t _08;
}; };
struct InitialProcessBinaryLayoutWithSize {
InitialProcessBinaryLayout layout;
size_t size;
};
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress(); KPhysicalAddress GetInitialProcessBinaryPhysicalAddress();
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr); size_t GetInitialProcessBinarySize();
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size);
u64 GetInitialProcessIdMin(); u64 GetInitialProcessIdMin();
u64 GetInitialProcessIdMax(); u64 GetInitialProcessIdMax();

View file

@ -171,6 +171,9 @@ namespace ams::kern::init {
const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion(); const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion();
KVirtualAddress address = slab_region.GetAddress(); KVirtualAddress address = slab_region.GetAddress();
/* Clear the slab region. */
std::memset(GetVoidPointer(address), 0, slab_region.GetSize());
/* Initialize slab type array to be in sorted order. */ /* Initialize slab type array to be in sorted order. */
KSlabType slab_types[KSlabType_Count]; KSlabType slab_types[KSlabType_Count];
for (size_t i = 0; i < util::size(slab_types); i++) { slab_types[i] = static_cast<KSlabType>(i); } for (size_t i = 0; i < util::size(slab_types); i++) { slab_types[i] = static_cast<KSlabType>(i); }

View file

@ -27,6 +27,7 @@ namespace ams::kern {
constinit KPhysicalAddress g_initial_process_binary_phys_addr = Null<KPhysicalAddress>; constinit KPhysicalAddress g_initial_process_binary_phys_addr = Null<KPhysicalAddress>;
constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>; constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>;
constinit size_t g_initial_process_binary_size = 0;
constinit InitialProcessBinaryHeader g_initial_process_binary_header = {}; constinit InitialProcessBinaryHeader g_initial_process_binary_header = {};
constinit size_t g_initial_process_secure_memory_size = 0; constinit size_t g_initial_process_secure_memory_size = 0;
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max(); constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
@ -275,10 +276,11 @@ namespace ams::kern {
} }
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr) { void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size) {
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr == Null<KPhysicalAddress>); MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr == Null<KPhysicalAddress>);
g_initial_process_binary_phys_addr = phys_addr; g_initial_process_binary_phys_addr = phys_addr;
g_initial_process_binary_size = size;
} }
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() { KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
@ -287,6 +289,12 @@ namespace ams::kern {
return g_initial_process_binary_phys_addr; return g_initial_process_binary_phys_addr;
} }
size_t GetInitialProcessBinarySize() {
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr != Null<KPhysicalAddress>);
return g_initial_process_binary_size;
}
u64 GetInitialProcessIdMin() { u64 GetInitialProcessIdMin() {
return g_initial_process_id_min; return g_initial_process_id_min;
} }
@ -305,14 +313,17 @@ namespace ams::kern {
LoadInitialProcessBinaryHeader(); LoadInitialProcessBinaryHeader();
if (g_initial_process_binary_header.num_processes > 0) { if (g_initial_process_binary_header.num_processes > 0) {
/* Reserve pages for the initial process binary from the system resource limit. */ /* Ensure that we have a non-zero size. */
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize); const size_t expected_size = g_initial_process_binary_size;
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size)); MESOSPHERE_INIT_ABORT_UNLESS(expected_size != 0);
/* The initial process binary is potentially over-allocated, so free any extra pages. */ /* Ensure that the size we need to reserve is as we expect it to be. */
if (total_size < InitialProcessBinarySizeMax) { const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(g_initial_process_binary_address + total_size), (InitialProcessBinarySizeMax - total_size) / PageSize); MESOSPHERE_ABORT_UNLESS(total_size == expected_size);
} MESOSPHERE_ABORT_UNLESS(total_size <= InitialProcessBinarySizeMax);
/* Reserve pages for the initial process binary from the system resource limit. */
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
return total_size; return total_size;
} else { } else {

View file

@ -108,7 +108,8 @@ namespace ams::kern {
/* Free each region to its corresponding heap. */ /* Free each region to its corresponding heap. */
size_t reserved_sizes[MaxManagerCount] = {}; size_t reserved_sizes[MaxManagerCount] = {};
const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress(); const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress();
const KPhysicalAddress ini_end = ini_start + InitialProcessBinarySizeMax; const size_t ini_size = GetInitialProcessBinarySize();
const KPhysicalAddress ini_end = ini_start + ini_size;
const KPhysicalAddress ini_last = ini_end - 1; const KPhysicalAddress ini_last = ini_end - 1;
for (const auto &it : KMemoryLayout::GetPhysicalMemoryRegionTree()) { for (const auto &it : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) { if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
@ -126,13 +127,13 @@ namespace ams::kern {
} }
/* Open/reserve the ini memory. */ /* Open/reserve the ini memory. */
manager.OpenFirst(ini_start, InitialProcessBinarySizeMax / PageSize); manager.OpenFirst(ini_start, ini_size / PageSize);
reserved_sizes[it.GetAttributes()] += InitialProcessBinarySizeMax; reserved_sizes[it.GetAttributes()] += ini_size;
/* Free memory after the ini to the heap. */ /* Free memory after the ini to the heap. */
if (ini_last != cur_last) { if (ini_last != cur_last) {
MESOSPHERE_ABORT_UNLESS(cur_end != Null<KPhysicalAddress>); MESOSPHERE_ABORT_UNLESS(cur_end != Null<KPhysicalAddress>);
manager.Free(ini_end, cur_end - ini_end); manager.Free(ini_end, (cur_end - ini_end) / PageSize);
} }
} else { } else {
/* Ensure there's no partial overlap with the ini image. */ /* Ensure there's no partial overlap with the ini image. */

View file

@ -45,7 +45,7 @@ namespace ams::kern::init {
constinit KInitArguments g_init_arguments[cpu::NumCores]; constinit KInitArguments g_init_arguments[cpu::NumCores];
/* Globals for passing data between InitializeCorePhase1 and InitializeCorePhase2. */ /* Globals for passing data between InitializeCorePhase1 and InitializeCorePhase2. */
constinit InitialProcessBinaryLayout g_phase2_initial_process_binary_layout{}; constinit InitialProcessBinaryLayoutWithSize g_phase2_initial_process_binary_meta{};
constinit KPhysicalAddress g_phase2_resource_end_phys_addr = Null<KPhysicalAddress>; constinit KPhysicalAddress g_phase2_resource_end_phys_addr = Null<KPhysicalAddress>;
constinit u64 g_phase2_linear_region_phys_to_virt_diff = 0; constinit u64 g_phase2_linear_region_phys_to_virt_diff = 0;
@ -246,7 +246,7 @@ namespace ams::kern::init {
/* Decode the initial state. */ /* Decode the initial state. */
const auto initial_page_allocator_state = *static_cast<KInitialPageAllocator::State *>(initial_state[0]); const auto initial_page_allocator_state = *static_cast<KInitialPageAllocator::State *>(initial_state[0]);
g_phase2_initial_process_binary_layout = *static_cast<InitialProcessBinaryLayout *>(initial_state[1]); g_phase2_initial_process_binary_meta = *static_cast<InitialProcessBinaryLayoutWithSize *>(initial_state[1]);
/* Restore the page allocator state setup by kernel loader. */ /* Restore the page allocator state setup by kernel loader. */
g_initial_page_allocator.InitializeFromState(std::addressof(initial_page_allocator_state)); g_initial_page_allocator.InitializeFromState(std::addressof(initial_page_allocator_state));
@ -565,9 +565,6 @@ namespace ams::kern::init {
} }
} }
/* Clear the slab region. */
std::memset(GetVoidPointer(slab_region_start), 0, slab_region_size);
/* NOTE: Unknown function is called here which is ifdef'd out on retail kernel. */ /* NOTE: Unknown function is called here which is ifdef'd out on retail kernel. */
/* The unknown function is immediately before the function which gets an unknown debug region size, inside this translation unit. */ /* The unknown function is immediately before the function which gets an unknown debug region size, inside this translation unit. */
/* It's likely that this is some kind of initializer for this unknown debug region. */ /* It's likely that this is some kind of initializer for this unknown debug region. */
@ -624,9 +621,10 @@ namespace ams::kern::init {
/* Set the initial process binary physical address. */ /* Set the initial process binary physical address. */
/* NOTE: Nintendo does this after pool partition setup, but it's a requirement that we do it before */ /* NOTE: Nintendo does this after pool partition setup, but it's a requirement that we do it before */
/* to retain compatibility with < 5.0.0. */ /* to retain compatibility with < 5.0.0. */
const KPhysicalAddress ini_address = g_phase2_initial_process_binary_layout.address; const KPhysicalAddress ini_address = g_phase2_initial_process_binary_meta.layout.address;
const size_t ini_size = g_phase2_initial_process_binary_meta.size;
MESOSPHERE_INIT_ABORT_UNLESS(ini_address != Null<KPhysicalAddress>); MESOSPHERE_INIT_ABORT_UNLESS(ini_address != Null<KPhysicalAddress>);
SetInitialProcessBinaryPhysicalAddress(ini_address); SetInitialProcessBinaryPhysicalAddress(ini_address, ini_size);
/* Setup all other memory regions needed to arrange the pool partitions. */ /* Setup all other memory regions needed to arrange the pool partitions. */
SetupPoolPartitionMemoryRegions(); SetupPoolPartitionMemoryRegions();
@ -640,7 +638,7 @@ namespace ams::kern::init {
/* Check that the region contains the ini. */ /* Check that the region contains the ini. */
MESOSPHERE_INIT_ABORT_UNLESS(ini_region->GetAddress() <= GetInteger(ini_address)); MESOSPHERE_INIT_ABORT_UNLESS(ini_region->GetAddress() <= GetInteger(ini_address));
MESOSPHERE_INIT_ABORT_UNLESS(GetInteger(ini_address) + InitialProcessBinarySizeMax <= ini_region->GetEndAddress()); MESOSPHERE_INIT_ABORT_UNLESS(GetInteger(ini_address) + ini_size <= ini_region->GetEndAddress());
MESOSPHERE_INIT_ABORT_UNLESS(ini_region->GetEndAddress() != 0); MESOSPHERE_INIT_ABORT_UNLESS(ini_region->GetEndAddress() != 0);
} }

View file

@ -45,7 +45,7 @@ namespace ams::kern::init::loader {
constinit KInitialPageAllocator g_initial_page_allocator; constinit KInitialPageAllocator g_initial_page_allocator;
constinit KInitialPageAllocator::State g_final_page_allocator_state; constinit KInitialPageAllocator::State g_final_page_allocator_state;
constinit InitialProcessBinaryLayout g_initial_process_binary_layout; constinit InitialProcessBinaryLayoutWithSize g_initial_process_binary_meta;
constinit void *g_final_state[2]; constinit void *g_final_state[2];
@ -165,19 +165,31 @@ namespace ams::kern::init::loader {
const uintptr_t resource_end_address = base_address + resource_offset + resource_region_size; const uintptr_t resource_end_address = base_address + resource_offset + resource_region_size;
/* Setup the INI1 header in memory for the kernel. */ /* Setup the INI1 header in memory for the kernel. */
KSystemControl::Init::GetInitialProcessBinaryLayout(std::addressof(g_initial_process_binary_layout)); {
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_layout.address != 0); /* Get the kernel layout. */
KSystemControl::Init::GetInitialProcessBinaryLayout(std::addressof(g_initial_process_binary_meta.layout));
if (ini_base_address != g_initial_process_binary_layout.address) { /* If there's no desired base address, use the ini in place. */
/* The INI is not at the correct address, so we need to relocate it. */ if (g_initial_process_binary_meta.layout.address == 0) {
g_initial_process_binary_meta.layout.address = ini_base_address;
}
/* Validate and potentially relocate the INI. */
const InitialProcessBinaryHeader *ini_header = reinterpret_cast<const InitialProcessBinaryHeader *>(ini_base_address); const InitialProcessBinaryHeader *ini_header = reinterpret_cast<const InitialProcessBinaryHeader *>(ini_base_address);
if (ini_header->magic == InitialProcessBinaryMagic && ini_header->size <= InitialProcessBinarySizeMax) { size_t ini_size = 0;
/* INI is valid, relocate it. */ if (ini_header->magic == InitialProcessBinaryMagic && (ini_size = ini_header->size) <= InitialProcessBinarySizeMax) {
std::memmove(reinterpret_cast<void *>(g_initial_process_binary_layout.address), ini_header, ini_header->size); /* INI is valid, relocate it if necessary. */
if (ini_base_address != g_initial_process_binary_meta.layout.address) {
std::memmove(reinterpret_cast<void *>(g_initial_process_binary_meta.layout.address), ini_header, ini_size);
}
} else { } else {
/* INI is invalid. Make the destination header invalid. */ /* INI is invalid. Make the destination header invalid. */
std::memset(reinterpret_cast<void *>(g_initial_process_binary_layout.address), 0, sizeof(InitialProcessBinaryHeader)); std::memset(reinterpret_cast<void *>(g_initial_process_binary_meta.layout.address), 0, sizeof(InitialProcessBinaryHeader));
} }
/* Set the INI size in layout. */
g_initial_process_binary_meta.size = util::AlignUp(ini_size, PageSize);
} }
/* We want to start allocating page tables at the end of the resource region. */ /* We want to start allocating page tables at the end of the resource region. */
@ -238,7 +250,7 @@ namespace ams::kern::init::loader {
/* Setup final kernel loader state. */ /* Setup final kernel loader state. */
g_final_state[0] = std::addressof(g_final_page_allocator_state); g_final_state[0] = std::addressof(g_final_page_allocator_state);
g_final_state[1] = std::addressof(g_initial_process_binary_layout); g_final_state[1] = std::addressof(g_initial_process_binary_meta);
return g_final_state; return g_final_state;
} }