diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 33c361c64..ffeac1848 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -271,6 +271,12 @@ namespace ams::kern::arch::arm64 { size_t GetNormalMemorySize() const { return this->page_table.GetNormalMemorySize(); } + size_t GetCodeSize() const { return this->page_table.GetCodeSize(); } + size_t GetCodeDataSize() const { return this->page_table.GetCodeDataSize(); } + + size_t GetAliasCodeSize() const { return this->page_table.GetAliasCodeSize(); } + size_t GetAliasCodeDataSize() const { return this->page_table.GetAliasCodeDataSize(); } + u32 GetAllocateOption() const { return this->page_table.GetAllocateOption(); } KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress address) const { diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp index 3854accf4..5cd8b0d90 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp @@ -63,6 +63,14 @@ namespace ams::kern::arch::arm64 { constexpr u64 GetIdentityMapTtbr0(s32 core_id) const { return this->ttbr0_identity[core_id]; } + void DumpMemoryBlocks() const { + return this->page_table.DumpMemoryBlocks(); + } + + void DumpPageTable() const { + return this->page_table.DumpPageTable(); + } + size_t CountPageTables() const { return this->page_table.CountPageTables(); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index ade036e75..5892534ec 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -30,6 +30,10 @@ namespace ams::kern::KDumpObject { void DumpHandle(); void DumpHandle(u64 process_id); + void DumpKernelMemory(); + void DumpMemory(); + void DumpMemory(u64 process_id); + void DumpProcess(); void DumpProcess(u64 process_id); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 18e42d97d..0f44b77b0 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -301,6 +301,8 @@ namespace ams::kern { Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state); Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send); void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm); + + size_t GetSize(KMemoryState state) const; public: bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const { return this->GetImpl().GetPhysicalAddress(out, virt_addr); @@ -423,6 +425,11 @@ namespace ams::kern { return (this->current_heap_end - this->heap_region_start) + this->mapped_physical_memory_size; } + size_t GetCodeSize() const; + size_t GetCodeDataSize() const; + size_t GetAliasCodeSize() const; + size_t GetAliasCodeDataSize() const; + u32 GetAllocateOption() const { return this->allocate_option; } public: static ALWAYS_INLINE KVirtualAddress GetLinearMappedVirtualAddress(KPhysicalAddress addr) { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 2066325fc..f58fe89ce 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -170,6 +170,8 @@ namespace ams::kern { constexpr KProcessAddress GetEntryPoint() const { return this->code_address; } + constexpr size_t GetMainStackSize() const { return this->main_thread_stack_size; } + constexpr KMemoryManager::Pool GetMemoryPool() const { return this->memory_pool; } constexpr u64 GetRandomEntropy(size_t i) const { return this->entropy[i]; } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 4a5d72a25..9fa4484a2 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -125,6 +125,47 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("\n\n"); } + void DumpMemory(KProcess *process) { + const auto process_id = process->GetId(); + MESOSPHERE_RELEASE_LOG("Process ID=%3lu (%s)\n", process_id, process->GetName()); + + /* Dump the memory blocks. */ + process->GetPageTable().DumpMemoryBlocks(); + + /* Collect information about memory totals. */ + const size_t code = process->GetPageTable().GetCodeSize(); + const size_t code_data = process->GetPageTable().GetCodeDataSize(); + const size_t alias_code = process->GetPageTable().GetAliasCodeSize(); + const size_t alias_code_data = process->GetPageTable().GetAliasCodeDataSize(); + const size_t normal = process->GetPageTable().GetNormalMemorySize(); + const size_t main_stack = process->GetMainStackSize(); + + size_t shared = 0; + { + KSharedMemory::ListAccessor accessor; + const auto end = accessor.end(); + for (auto it = accessor.begin(); it != end; ++it) { + KSharedMemory *shared_mem = static_cast(std::addressof(*it)); + if (shared_mem->GetOwnerProcessId() == process_id) { + shared += shared_mem->GetSize(); + } + } + } + + /* Dump the totals. */ + MESOSPHERE_RELEASE_LOG("---\n"); + MESOSPHERE_RELEASE_LOG("Code %8zu KB\n", code / 1_KB); + MESOSPHERE_RELEASE_LOG("CodeData %8zu KB\n", code_data / 1_KB); + MESOSPHERE_RELEASE_LOG("AliasCode %8zu KB\n", alias_code / 1_KB); + MESOSPHERE_RELEASE_LOG("AliasCodeData %8zu KB\n", alias_code_data / 1_KB); + MESOSPHERE_RELEASE_LOG("Heap %8zu KB\n", normal / 1_KB); + MESOSPHERE_RELEASE_LOG("SharedMemory %8zu KB\n", shared / 1_KB); + MESOSPHERE_RELEASE_LOG("InitialStack %8zu KB\n", main_stack / 1_KB); + MESOSPHERE_RELEASE_LOG("---\n"); + MESOSPHERE_RELEASE_LOG("TOTAL %8zu KB\n", (code + code_data + alias_code + alias_code_data + normal + main_stack + shared) / 1_KB); + MESOSPHERE_RELEASE_LOG("\n\n"); + } + void DumpProcess(KProcess *process) { MESOSPHERE_RELEASE_LOG("Process ID=%3lu index=%3zu State=%d (%s)\n", process->GetId(), process->GetSlabIndex(), process->GetState(), process->GetName()); } @@ -501,6 +542,47 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("\n"); } + void DumpKernelMemory() { + MESOSPHERE_RELEASE_LOG("Dump Kernel Memory Info\n"); + + { + Kernel::GetKernelPageTable().DumpMemoryBlocks(); + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpMemory() { + MESOSPHERE_RELEASE_LOG("Dump Memory Info\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpMemory(static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpMemory(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Memory Info\n"); + + { + /* Find and dump the target process. */ + if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + DumpMemory(process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + void DumpProcess() { MESOSPHERE_RELEASE_LOG("Dump Process\n"); diff --git a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp index c6bcc2147..8cbbe4be7 100644 --- a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp @@ -81,7 +81,7 @@ namespace ams::kern { const char d = (info.attribute & KMemoryAttribute_DeviceShared) ? 'D' : '-'; const char u = (info.attribute & KMemoryAttribute_Uncached) ? 'U' : '-'; - MESOSPHERE_LOG("%p - %p (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, info.ipc_lock_count, info.device_use_count); + MESOSPHERE_LOG("0x%10lx - 0x%10lx (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, info.ipc_lock_count, info.device_use_count); } } diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 289b04fe5..b7805d94f 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -1018,6 +1018,39 @@ namespace ams::kern { return address; } + size_t KPageTableBase::GetSize(KMemoryState state) const { + /* Lock the table. */ + KScopedLightLock lk(this->general_lock); + + /* Iterate, counting blocks with the desired state. */ + size_t total_size = 0; + for (KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(this->address_space_start); it != this->memory_block_manager.end(); ++it) { + /* Get the memory info. */ + const KMemoryInfo info = it->GetMemoryInfo(); + if (info.GetState() == state) { + total_size += info.GetSize(); + } + } + + return total_size; + } + + size_t KPageTableBase::GetCodeSize() const { + return this->GetSize(KMemoryState_Code); + } + + size_t KPageTableBase::GetCodeDataSize() const { + return this->GetSize(KMemoryState_CodeData); + } + + size_t KPageTableBase::GetAliasCodeSize() const { + return this->GetSize(KMemoryState_AliasCode); + } + + size_t KPageTableBase::GetAliasCodeDataSize() const { + return this->GetSize(KMemoryState_AliasCodeData); + } + Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, KMemoryPermission perm) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index d16643cd6..a94b35894 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -51,6 +51,15 @@ namespace ams::kern::svc { KDumpObject::DumpHandle(arg0); } break; + case ams::svc::KernelDebugType_Memory: + if (arg0 == static_cast(-2)) { + KDumpObject::DumpKernelMemory(); + } else if (arg0 == static_cast(-1)) { + KDumpObject::DumpMemory(); + } else { + KDumpObject::DumpMemory(arg0); + } + break; case ams::svc::KernelDebugType_Process: if (arg0 == static_cast(-1)) { KDumpObject::DumpProcess(); diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index e5f048798..b533d4e03 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -474,7 +474,9 @@ namespace ams::svc { KernelDebugType_ThreadCallStack = 1, KernelDebugType_KernelObject = 2, KernelDebugType_Handle = 3, - + KernelDebugType_Memory = 4, + KernelDebugType_PageTable = 5, + KernelDebugType_CpuUtilization = 6, KernelDebugType_Process = 7, KernelDebugType_SuspendProcess = 8, KernelDebugType_ResumeProcess = 9,