From 423a05a1e90bf711f724b8d2a723dbbb5e0d5281 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 1 Sep 2024 16:27:01 -0700 Subject: [PATCH 1/4] meso: fix sign-comparison warn on svc/interrupt flag compare --- .../libmesosphere/include/mesosphere/kern_k_capabilities.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp index 7b5a93dcc..7c2f5dbcd 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp @@ -192,7 +192,7 @@ namespace ams::kern { u32 m_program_type; private: constexpr bool SetSvcAllowed(u32 id) { - if (AMS_LIKELY(id < m_svc_access_flags.GetCount())) { + if (AMS_LIKELY(id < static_cast(m_svc_access_flags.GetCount()))) { m_svc_access_flags[id] = true; return true; } else { @@ -201,7 +201,7 @@ namespace ams::kern { } constexpr bool SetInterruptPermitted(u32 id) { - if (AMS_LIKELY(id < m_irq_access_flags.GetCount())) { + if (AMS_LIKELY(id < static_cast(m_irq_access_flags.GetCount()))) { m_irq_access_flags[id] = true; return true; } else { From 027e209073cd46265f0483c4502f6b55a3c9f26a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 1 Sep 2024 22:27:48 -0700 Subject: [PATCH 2/4] kern/ldr: enable the use of relr for relocations --- mesosphere/kernel/kernel.ld | 3 +++ mesosphere/kernel/kernel.specs | 2 +- .../kernel/source/arch/arm64/init/kern_init_core.cpp | 8 ++++---- mesosphere/kernel_ldr/kernel_ldr.ld | 7 ++++--- mesosphere/kernel_ldr/kernel_ldr.specs | 2 +- mesosphere/kernel_ldr/source/kern_init_loader.cpp | 8 ++++---- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/mesosphere/kernel/kernel.ld b/mesosphere/kernel/kernel.ld index 356cea88c..779488a35 100644 --- a/mesosphere/kernel/kernel.ld +++ b/mesosphere/kernel/kernel.ld @@ -14,6 +14,7 @@ SECTIONS /* =========== CODE section =========== */ PROVIDE(__start__ = 0x0); . = __start__; + __bin_start__ = .; __code_start = . ; .start : @@ -159,6 +160,7 @@ SECTIONS __bss_start__ = .; .rela.dyn : { *(.rela.*) } :data + .relr.dyn : { *(.relr.*) } :data .bss ADDR(.rela.dyn) (NOLOAD) : { *(.dynbss) @@ -169,6 +171,7 @@ SECTIONS __bss_end__ = .; + __bin_end__ = .; __end__ = ABSOLUTE(.); /* ================== diff --git a/mesosphere/kernel/kernel.specs b/mesosphere/kernel/kernel.specs index 7ca30e94d..a6b848cd0 100644 --- a/mesosphere/kernel/kernel.specs +++ b/mesosphere/kernel/kernel.specs @@ -1,7 +1,7 @@ %rename link old_link *link: -%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /kernel.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -nostdlib +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /kernel.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -z pack-relative-relocs -nostdlib *startfile: crti%O%s crtbegin%O%s diff --git a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp index f74cb050c..faf34576d 100644 --- a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp +++ b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp @@ -15,8 +15,8 @@ */ #include -extern "C" void _start(); -extern "C" void __end__(); +extern "C" void __bin_start__(); +extern "C" void __bin_end__(); namespace ams::kern { @@ -264,8 +264,8 @@ namespace ams::kern::init { KMemoryLayout::GetPhysicalMemoryRegionTree().InsertDirectly(KernelPhysicalAddressSpaceBase, KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1); /* Save start and end for ease of use. */ - const uintptr_t code_start_virt_addr = reinterpret_cast(_start); - const uintptr_t code_end_virt_addr = reinterpret_cast(__end__); + const uintptr_t code_start_virt_addr = reinterpret_cast(__bin_start__); + const uintptr_t code_end_virt_addr = reinterpret_cast(__bin_end__); /* Setup the containing kernel region. */ constexpr size_t KernelRegionSize = 1_GB; diff --git a/mesosphere/kernel_ldr/kernel_ldr.ld b/mesosphere/kernel_ldr/kernel_ldr.ld index c56886133..26802a6f3 100644 --- a/mesosphere/kernel_ldr/kernel_ldr.ld +++ b/mesosphere/kernel_ldr/kernel_ldr.ld @@ -12,6 +12,7 @@ SECTIONS /* =========== CODE section =========== */ PROVIDE(__start__ = 0x0); . = __start__; + __bin_start__ = .; __code_start = . ; .crt0 : @@ -74,9 +75,8 @@ SECTIONS .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } : rodata .dynamic : { *(.dynamic) } :krnlldr :dyn - .dynsym : { *(.dynsym) } :krnlldr - .dynstr : { *(.dynstr) } :krnlldr .rela.dyn : { *(.rela.*) } :krnlldr + .relr.dyn : { *(.relr.*) } :krnlldr .hash : { *(.hash) } :krnlldr .gnu.hash : { *(.gnu.hash) } :krnlldr .gnu.version : { *(.gnu.version) } :krnlldr @@ -159,6 +159,7 @@ SECTIONS } :krnlldr __bss_end__ = .; + __bin_end__ = .; __end__ = ABSOLUTE(.) ; /* ================== @@ -166,7 +167,7 @@ SECTIONS ================== */ /* Discard sections that difficult post-processing */ - /DISCARD/ : { *(.group .comment .note .interp) } + /DISCARD/ : { *(.group .comment .note .interp .dynsym .dynstr) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff --git a/mesosphere/kernel_ldr/kernel_ldr.specs b/mesosphere/kernel_ldr/kernel_ldr.specs index 593f42369..42d7e341e 100644 --- a/mesosphere/kernel_ldr/kernel_ldr.specs +++ b/mesosphere/kernel_ldr/kernel_ldr.specs @@ -1,7 +1,7 @@ %rename link old_link *link: -%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /kernel_ldr.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -nostdlib +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /kernel_ldr.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -z pack-relative-relocs -nostdlib *startfile: crti%O%s crtbegin%O%s diff --git a/mesosphere/kernel_ldr/source/kern_init_loader.cpp b/mesosphere/kernel_ldr/source/kern_init_loader.cpp index 8b991d943..33fe56393 100644 --- a/mesosphere/kernel_ldr/source/kern_init_loader.cpp +++ b/mesosphere/kernel_ldr/source/kern_init_loader.cpp @@ -19,8 +19,8 @@ /* Necessary for calculating kernelldr size/base for initial identity mapping */ extern "C" { - extern const u8 __start__[]; - extern const u8 __end__[]; + extern const u8 __bin_start__[]; + extern const u8 __bin_end__[]; } @@ -88,8 +88,8 @@ namespace ams::kern::init::loader { /* Map in an RWX identity mapping for ourselves. */ constexpr PageTableEntry KernelLdrRWXIdentityAttribute(PageTableEntry::Permission_KernelRWX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped); - const uintptr_t kernel_ldr_base = util::AlignDown(reinterpret_cast(__start__), PageSize); - const uintptr_t kernel_ldr_size = util::AlignUp(reinterpret_cast(__end__), PageSize) - kernel_ldr_base; + const uintptr_t kernel_ldr_base = util::AlignDown(reinterpret_cast(__bin_start__), PageSize); + const uintptr_t kernel_ldr_size = util::AlignUp(reinterpret_cast(__bin_end__), PageSize) - kernel_ldr_base; init_pt.Map(kernel_ldr_base, kernel_ldr_size, kernel_ldr_base, KernelRWXIdentityAttribute, allocator, 0); /* Map in the page table region as RW- for ourselves. */ From 009f58172118f850f08655dc5f4d8a3ff3d50027 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 23 Sep 2024 02:41:57 -0700 Subject: [PATCH 3/4] creport: optimize ScopedFile performance --- .../creport/source/creport_crash_report.cpp | 12 +++++- .../creport/source/creport_modules.cpp | 2 +- .../creport/source/creport_scoped_file.cpp | 42 +++++++++++++++---- .../creport/source/creport_scoped_file.hpp | 11 ++++- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/stratosphere/creport/source/creport_crash_report.cpp b/stratosphere/creport/source/creport_crash_report.cpp index 9936102e5..fec6cbc67 100644 --- a/stratosphere/creport/source/creport_crash_report.cpp +++ b/stratosphere/creport/source/creport_crash_report.cpp @@ -26,6 +26,8 @@ namespace ams::creport { static_assert(DyingMessageAddressOffset == AMS_OFFSETOF(ams::svc::aarch64::ProcessLocalRegion, dying_message_region_address)); static_assert(DyingMessageAddressOffset == AMS_OFFSETOF(ams::svc::aarch32::ProcessLocalRegion, dying_message_region_address)); + constexpr size_t CrashReportDataCacheSize = 256_KB; + /* Helper functions. */ bool TryGetCurrentTimestamp(u64 *out) { /* Clear output. */ @@ -307,7 +309,15 @@ namespace ams::creport { /* Save crash report. */ util::SNPrintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/%011lu_%016lx.log", timestamp, m_process_info.program_id); { - ScopedFile file(file_path); + /* Try to allocate data cache. */ + void * const data_cache = lmem::AllocateFromExpHeap(m_heap_handle, CrashReportDataCacheSize + os::MemoryPageSize); + ON_SCOPE_EXIT { if (data_cache != nullptr) { lmem::FreeToExpHeap(m_heap_handle, data_cache); } }; + + /* Align up the data cache. This is safe because null will align up to null. */ + void * const aligned_cache = reinterpret_cast(util::AlignUp(reinterpret_cast(data_cache), os::MemoryPageSize)); + + /* Open and save the file using the cache. */ + ScopedFile file(file_path, aligned_cache, aligned_cache != nullptr ? CrashReportDataCacheSize : 0); if (file.IsOpen()) { this->SaveToFile(file); } diff --git a/stratosphere/creport/source/creport_modules.cpp b/stratosphere/creport/source/creport_modules.cpp index 69620b92b..b6a3486e1 100644 --- a/stratosphere/creport/source/creport_modules.cpp +++ b/stratosphere/creport/source/creport_modules.cpp @@ -46,7 +46,7 @@ namespace ams::creport { } void ModuleList::SaveToFile(ScopedFile &file) { - file.WriteFormat(" Number of Modules: %zu\n", m_num_modules); + file.WriteFormat(" Number of Modules: %02zu\n", m_num_modules); for (size_t i = 0; i < m_num_modules; i++) { const auto& module = m_modules[i]; file.WriteFormat(" Module %02zu:\n", i); diff --git a/stratosphere/creport/source/creport_scoped_file.cpp b/stratosphere/creport/source/creport_scoped_file.cpp index 4daf9e046..1b6341c99 100644 --- a/stratosphere/creport/source/creport_scoped_file.cpp +++ b/stratosphere/creport/source/creport_scoped_file.cpp @@ -60,22 +60,24 @@ namespace ams::creport { /* Print the line prefix. */ if (first) { - this->WriteFormat("%s", prefix); + this->Write(prefix, prefix_len); first = false; } else { - this->WriteFormat("%*s", prefix_len, ""); + std::memset(g_format_buffer, ' ', prefix_len); + this->Write(g_format_buffer, prefix_len); } /* Dump up to 0x20 of hex memory. */ { char hex[MaximumLineLength * 2 + 2] = {}; for (size_t i = 0; i < cur_size; i++) { - util::SNPrintf(hex + i * 2, 3, "%02X", data_u8[data_ofs++]); + hex[i * 2 + 0] = "0123456789ABCDEF"[data_u8[data_ofs] >> 4]; + hex[i * 2 + 1] = "0123456789ABCDEF"[data_u8[data_ofs] & 0xF]; + ++data_ofs; } hex[cur_size * 2 + 0] = '\n'; - hex[cur_size * 2 + 1] = '\x00'; - this->WriteString(hex); + this->Write(hex, cur_size * 2 + 1); } /* Continue. */ @@ -83,16 +85,40 @@ namespace ams::creport { } } + void ScopedFile::Write(const void *data, size_t size) { /* If we're not open, we can't write. */ if (!this->IsOpen()) { return; } - /* Advance, if we write successfully. */ - if (R_SUCCEEDED(fs::WriteFile(m_file, m_offset, data, size, fs::WriteOption::Flush))) { - m_offset += size; + /* If we have a cache, write to it. */ + if (m_cache != nullptr) { + /* Write into the cache, if we can. */ + if (m_cache_size - m_cache_offset >= size || R_SUCCEEDED(this->TryWriteCache())) { + std::memcpy(m_cache + m_cache_offset, data, size); + m_cache_offset += size; + } + } else { + /* Advance, if we write successfully. */ + if (R_SUCCEEDED(fs::WriteFile(m_file, m_offset, data, size, fs::WriteOption::None))) { + m_offset += size; + } } } + Result ScopedFile::TryWriteCache() { + /* If there's no cached data, there's nothing to do. */ + R_SUCCEED_IF(m_cache_offset == 0); + + /* Try to write any cached data. */ + R_TRY(fs::WriteFile(m_file, m_offset, m_cache, m_cache_offset, fs::WriteOption::None)); + + /* Update our extents. */ + m_offset += m_cache_offset; + m_cache_offset = 0; + + R_SUCCEED(); + } + } \ No newline at end of file diff --git a/stratosphere/creport/source/creport_scoped_file.hpp b/stratosphere/creport/source/creport_scoped_file.hpp index 7b302b589..5adcbeb09 100644 --- a/stratosphere/creport/source/creport_scoped_file.hpp +++ b/stratosphere/creport/source/creport_scoped_file.hpp @@ -25,8 +25,11 @@ namespace ams::creport { fs::FileHandle m_file; s64 m_offset; bool m_opened; + u8 *m_cache; + const size_t m_cache_size; + s64 m_cache_offset; public: - ScopedFile(const char *path) : m_file(), m_offset(), m_opened(false) { + ScopedFile(const char *path, void *cache = nullptr, size_t cache_size = 0) : m_file(), m_offset(), m_opened(false), m_cache(static_cast(cache)), m_cache_size(cache_size), m_cache_offset(0) { if (R_SUCCEEDED(fs::CreateFile(path, 0))) { m_opened = R_SUCCEEDED(fs::OpenFile(std::addressof(m_file), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend)); } @@ -34,6 +37,10 @@ namespace ams::creport { ~ScopedFile() { if (m_opened) { + if (m_cache != nullptr) { + this->TryWriteCache(); + } + fs::FlushFile(m_file); fs::CloseFile(m_file); } } @@ -47,6 +54,8 @@ namespace ams::creport { void DumpMemory(const char *prefix, const void *data, size_t size); void Write(const void *data, size_t size); + private: + Result TryWriteCache(); }; } \ No newline at end of file From 10c7a395285c133e4c17c52d84728a4c7b24accd Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 24 Sep 2024 13:15:21 -0700 Subject: [PATCH 4/4] kern/creport: use mod0 to locate symbol table for all modules --- .../source/arch/arm64/kern_k_debug.cpp | 41 ++++++++----------- .../creport/source/creport_modules.cpp | 38 +++++------------ 2 files changed, 26 insertions(+), 53 deletions(-) diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp index eb04243cf..89587597b 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp @@ -623,11 +623,6 @@ namespace ams::kern::arch::arm64 { } } - /* Read the first instruction. */ - if (!ReadValue(std::addressof(temp_32), process, base_address)) { - return PrintAddress(address); - } - /* Get the module name. */ char module_name[0x20]; const bool has_module_name = GetModuleName(module_name, sizeof(module_name), process, base_address); @@ -637,36 +632,32 @@ namespace ams::kern::arch::arm64 { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - if (temp_32 == 0) { - /* Module is dynamically loaded by rtld. */ + /* Locate .dyn using rocrt::ModuleHeader. */ + { + /* Determine the ModuleHeader offset. */ u32 mod_offset; if (!ReadValue(std::addressof(mod_offset), process, base_address + sizeof(u32))) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset)) { + + /* Read the signature. */ + constexpr u32 SignatureFieldOffset = AMS_OFFSETOF(rocrt::ModuleHeader, signature); + if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset + SignatureFieldOffset)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - if (temp_32 != 0x30444F4D) { /* MOD0 */ + + /* Check that the module signature is expected. */ + if (temp_32 != rocrt::ModuleHeaderVersion) { /* MOD0 */ return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset + sizeof(u32))) { + + /* Determine the dynamic offset. */ + constexpr u32 DynamicFieldOffset = AMS_OFFSETOF(rocrt::ModuleHeader, dynamic_offset); + if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset + DynamicFieldOffset)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - dyn_address = base_address + mod_offset + temp_32; - } else if (temp_32 == 0x14000002) { - /* Module embeds rtld. */ - if (!ReadValue(std::addressof(temp_32), process, base_address + 0x5C)) { - return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); - } - if (temp_32 != 0x94000002) { - return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); - } - if (!ReadValue(std::addressof(temp_32), process, base_address + 0x60)) { - return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); - } - dyn_address = base_address + 0x60 + temp_32; - } else { - return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + + dyn_address = module.start_address + mod_offset + temp_32; } /* Locate tables inside .dyn. */ diff --git a/stratosphere/creport/source/creport_modules.cpp b/stratosphere/creport/source/creport_modules.cpp index b6a3486e1..7ea58e0dd 100644 --- a/stratosphere/creport/source/creport_modules.cpp +++ b/stratosphere/creport/source/creport_modules.cpp @@ -282,56 +282,38 @@ namespace ams::creport { return; } - /* Read the first instruction of .text. */ - if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(temp_32)), m_debug_handle, module.start_address, sizeof(temp_32)))) { - return; - } - /* We want to find the symbol table/.dynamic. */ uintptr_t dyn_address = 0; uintptr_t sym_tab = 0; uintptr_t str_tab = 0; size_t num_sym = 0; - /* Detect module type. */ - if (temp_32 == 0) { - /* Module is dynamically loaded by rtld. */ + /* Locate .dyn using rocrt::ModuleHeader. */ + { + /* Determine the ModuleHeader offset. */ u32 mod_offset; if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(mod_offset)), m_debug_handle, module.start_address + sizeof(u32), sizeof(u32)))) { return; } - if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(temp_32)), m_debug_handle, module.start_address + mod_offset, sizeof(u32)))) { + /* Read the signature. */ + constexpr u32 SignatureFieldOffset = AMS_OFFSETOF(rocrt::ModuleHeader, signature); + if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(temp_32)), m_debug_handle, module.start_address + mod_offset + SignatureFieldOffset, sizeof(u32)))) { return; } + /* Check that the module signature is expected. */ if (temp_32 != rocrt::ModuleHeaderVersion) { /* MOD0 */ return; } - if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(temp_32)), m_debug_handle, module.start_address + mod_offset + sizeof(u32), sizeof(u32)))) { + /* Determine the dynamic offset. */ + constexpr u32 DynamicFieldOffset = AMS_OFFSETOF(rocrt::ModuleHeader, dynamic_offset); + if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(temp_32)), m_debug_handle, module.start_address + mod_offset + DynamicFieldOffset, sizeof(u32)))) { return; } dyn_address = module.start_address + mod_offset + temp_32; - } else if (temp_32 == 0x14000002) { - /* Module embeds rtld. */ - if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(temp_32)), m_debug_handle, module.start_address + 0x5C, sizeof(u32)))) { - return; - } - - if (temp_32 != 0x94000002) { - return; - } - - if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast(std::addressof(temp_32)), m_debug_handle, module.start_address + 0x60, sizeof(u32)))) { - return; - } - - dyn_address = module.start_address + 0x60 + temp_32; - } else { - /* Module has unknown format. */ - return; }