From 0daef4a6e8bbf40c0aa31ca34d89d86614b2894d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 11 Oct 2023 02:59:41 -0700 Subject: [PATCH] kern/ldr: move crt0 into .rodata --- fusee/program/source/fusee_stratosphere.cpp | 18 +- .../mesosphere/init/kern_init_layout.hpp | 16 +- mesosphere/build_mesosphere.py | 17 +- mesosphere/kernel/kernel.ld | 44 ++--- .../kernel/source/arch/arm64/init/start.s | 161 +++++++++++------- .../kernel_ldr/source/arch/arm64/start.s | 20 ++- .../kernel_ldr/source/kern_init_loader.cpp | 34 +++- 7 files changed, 220 insertions(+), 90 deletions(-) diff --git a/fusee/program/source/fusee_stratosphere.cpp b/fusee/program/source/fusee_stratosphere.cpp index 3146b4c8b..f18bc4646 100644 --- a/fusee/program/source/fusee_stratosphere.cpp +++ b/fusee/program/source/fusee_stratosphere.cpp @@ -24,6 +24,9 @@ namespace ams::nxboot { namespace { + constexpr u32 MesoshereMetadataLayout0Magic = util::FourCC<'M','S','S','0'>::Code; + constexpr u32 MesoshereMetadataLayout1Magic = util::FourCC<'M','S','S','1'>::Code; + struct InitialProcessBinaryHeader { static constexpr u32 Magic = util::FourCC<'I','N','I','1'>::Code; @@ -1011,7 +1014,20 @@ namespace ams::nxboot { } /* Set the embedded ini pointer. */ - std::memcpy(payload_data + 8, std::addressof(meso_size), sizeof(meso_size)); + const u32 magic = *reinterpret_cast(payload_data + 4); + if (magic == MesoshereMetadataLayout0Magic) { + std::memcpy(payload_data + 8, std::addressof(meso_size), sizeof(meso_size)); + } else if (magic == MesoshereMetadataLayout1Magic) { + if (const u32 meta_offset = *reinterpret_cast(payload_data + 8); meta_offset <= meso_size - sizeof(meso_size)) { + s64 relative_offset = meso_size - meta_offset; + std::memcpy(payload_data + meta_offset, std::addressof(relative_offset), sizeof(relative_offset)); + } else { + ShowFatalError("Invalid mesosphere metadata layout!\n"); + } + } else { + ShowFatalError("Unknown mesosphere metadata version!\n"); + } + /* Get the ini pointer. */ InitialProcessBinaryHeader * const ini = reinterpret_cast(payload_data + meso_size); diff --git a/libraries/libmesosphere/include/mesosphere/init/kern_init_layout.hpp b/libraries/libmesosphere/include/mesosphere/init/kern_init_layout.hpp index daf0e81a4..db952edf4 100644 --- a/libraries/libmesosphere/include/mesosphere/init/kern_init_layout.hpp +++ b/libraries/libmesosphere/include/mesosphere/init/kern_init_layout.hpp @@ -31,8 +31,22 @@ namespace ams::kern::init { u32 dynamic_offset; u32 init_array_offset; u32 init_array_end_offset; + u32 sysreg_offset; }; static_assert(util::is_pod::value); - static_assert(sizeof(KernelLayout) == 0x30); + static_assert(sizeof(KernelLayout) == 0x34); + + #if defined(ATMOSPHERE_ARCH_ARM64) + struct KernelSystemRegisters { + u64 ttbr0_el1; + u64 ttbr1_el1; + u64 tcr_el1; + u64 mair_el1; + u64 sctlr_el1; + }; + #else + struct KernelSystemRegisters { + }; + #endif } \ No newline at end of file diff --git a/mesosphere/build_mesosphere.py b/mesosphere/build_mesosphere.py index 5b9dd4f7b..db9599763 100644 --- a/mesosphere/build_mesosphere.py +++ b/mesosphere/build_mesosphere.py @@ -17,11 +17,16 @@ def main(argc, argv): kernel_ldr = f.read() with open(argv[2], 'rb') as f: kernel = f.read() - kernel_metadata_offset = 4 + kernel_metaptr_offset = 4 + assert (kernel_metaptr_offset <= len(kernel) - 0x40) + assert (kernel[kernel_metaptr_offset:kernel_metaptr_offset + 4] == b'MSS1') + kernel_metadata_offset = up('= bss_start) assert (bss_end == kernel_end) @@ -53,9 +58,9 @@ def main(argc, argv): mesosphere_end = align_up(kernel_ldr_end, 0x1000) with open(argv[3], 'wb') as f: - f.write(kernel[:kernel_metadata_offset + 4]) - f.write(pk('(layout) - base_address; + layout->rx_offset += layout_offset; + layout->rx_end_offset += layout_offset; + layout->ro_offset += layout_offset; + layout->ro_end_offset += layout_offset; + layout->rw_offset += layout_offset; + layout->rw_end_offset += layout_offset; + layout->bss_offset += layout_offset; + layout->bss_end_offset += layout_offset; + layout->resource_offset += layout_offset; + layout->dynamic_offset += layout_offset; + layout->init_array_offset += layout_offset; + layout->init_array_end_offset += layout_offset; + layout->sysreg_offset += layout_offset; + } + + /* Relocate the kernel if necessary. */ KPhysicalAddress correct_base = KSystemControl::Init::GetKernelPhysicalBaseAddress(base_address); if (correct_base != base_address) { const uintptr_t diff = GetInteger(correct_base) - base_address; @@ -62,7 +81,7 @@ namespace ams::kern::init::loader { } } - void SetupInitialIdentityMapping(KInitialPageTable &init_pt, uintptr_t base_address, uintptr_t kernel_size, uintptr_t page_table_region, size_t page_table_region_size, KInitialPageAllocator &allocator) { + void SetupInitialIdentityMapping(KInitialPageTable &init_pt, uintptr_t base_address, uintptr_t kernel_size, uintptr_t page_table_region, size_t page_table_region_size, KInitialPageAllocator &allocator, KernelSystemRegisters *sysregs) { /* Map in an RWX identity mapping for the kernel. */ constexpr PageTableEntry KernelRWXIdentityAttribute(PageTableEntry::Permission_KernelRWX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped); init_pt.Map(base_address, kernel_size, base_address, KernelRWXIdentityAttribute, allocator, 0); @@ -96,9 +115,17 @@ namespace ams::kern::init::loader { /* Setup SCTLR_EL1. */ /* TODO: Define these bits properly elsewhere, document exactly what each bit set is doing .*/ - constexpr u64 SctlrValue = 0x0000000034D5D925ul; + constexpr u64 SctlrValue = 0x0000000034D5D92Dul; cpu::SetSctlrEl1(SctlrValue); cpu::InstructionMemoryBarrier(); + + /* Setup the system registers for other cores. */ + /* NOTE: sctlr_el1 on other cores has the WXN bit set (0x80000); this will be set before KernelMain() on this core. */ + sysregs->ttbr0_el1 = init_pt.GetTtbr0L1TableAddress(); + sysregs->ttbr1_el1 = init_pt.GetTtbr1L1TableAddress(); + sysregs->tcr_el1 = TcrValue; + sysregs->mair_el1 = MairValue; + sysregs->sctlr_el1 = SctlrValue | 0x80000; } KVirtualAddress GetRandomKernelBaseAddress(KInitialPageTable &page_table, KPhysicalAddress phys_base_address, size_t kernel_size) { @@ -159,6 +186,7 @@ namespace ams::kern::init::loader { const uintptr_t dynamic_offset = layout->dynamic_offset; const uintptr_t init_array_offset = layout->init_array_offset; const uintptr_t init_array_end_offset = layout->init_array_end_offset; + const uintptr_t sysreg_offset = layout->sysreg_offset; /* Determine the size of the resource region. */ const size_t resource_region_size = KMemoryLayout::GetResourceRegionSizeForInit(KSystemControl::Init::ShouldIncreaseThreadResourceLimit()); @@ -199,7 +227,7 @@ namespace ams::kern::init::loader { KInitialPageTable init_pt(KernelBaseRangeStart, KernelBaseRangeLast, g_initial_page_allocator); /* Setup initial identity mapping. TTBR1 table passed by reference. */ - SetupInitialIdentityMapping(init_pt, base_address, bss_end_offset, resource_end_address, InitialPageTableRegionSizeMax, g_initial_page_allocator); + SetupInitialIdentityMapping(init_pt, base_address, bss_end_offset, resource_end_address, InitialPageTableRegionSizeMax, g_initial_page_allocator, reinterpret_cast(base_address + sysreg_offset)); /* Generate a random slide for the kernel's base address. */ const KVirtualAddress virtual_base_address = GetRandomKernelBaseAddress(init_pt, base_address, bss_end_offset);