From f1a28f7a1c3f8db8a42828dd81af397599270122 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 5 Jul 2020 21:21:08 +0100 Subject: [PATCH] Fix the behaviour of svcQueryMemory and allow getting the extents of unmapped regions svcQueryMemory will return a valid descriptor for anything in the address space, from 0 to 1 << addrSpaceBits, this was handled incorrectly before and we were only returning descriptors if the address was in a mapped region. If an address in an unmapped region is requested then the extents of the unmapped region up to the address space end are returned. If the address requested is outside of the address space then the extents of the inaccessible address space are returned. To facilitate this support was added to MemoryManager::Get for generating the extents of unmapped regions using the chunk list. --- app/src/main/cpp/skyline/kernel/memory.cpp | 44 +++++++++++++++++++++- app/src/main/cpp/skyline/kernel/memory.h | 6 ++- app/src/main/cpp/skyline/kernel/svc.cpp | 13 +++---- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index ba34f6c0..e33fdc77 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -124,6 +124,8 @@ namespace skyline::kernel { throw exception("32-bit address spaces are not supported"); case memory::AddressSpaceType::AddressSpace36Bit: { + addressSpace.address = 0; + addressSpace.size = 1UL << 36; base.address = constant::BaseAddress; base.size = 0xFF8000000; code.address = base.address; @@ -142,6 +144,8 @@ namespace skyline::kernel { } case memory::AddressSpaceType::AddressSpace39Bit: { + addressSpace.address = 0; + addressSpace.size = 1UL << 39; base.address = constant::BaseAddress; base.size = 0x7FF8000000; code.address = util::AlignDown(address, 0x200000); @@ -164,12 +168,50 @@ namespace skyline::kernel { MemoryManager::MemoryManager(const DeviceState &state) : state(state) {} - std::optional MemoryManager::Get(u64 address) { + std::optional MemoryManager::Get(u64 address, bool requireMapped) { auto chunk = GetChunk(address); if (chunk) return DescriptorPack{*GetBlock(address, chunk), *chunk}; + // If the requested address is in the address space but no chunks are present then we return a new unmapped region + if (addressSpace.IsInside(address) && !requireMapped) { + auto upperChunk = std::upper_bound(chunkList.begin(), chunkList.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool { + return address < chunk.address; + }); + + u64 upperAddress{}; + u64 lowerAddress{}; + + if (upperChunk != chunkList.end()) { + upperAddress = upperChunk->address; + + if (upperChunk == chunkList.begin()) { + lowerAddress = addressSpace.address; + } else { + upperChunk--; + lowerAddress = upperChunk->address + upperChunk->size; + } + } else { + upperAddress = addressSpace.address + addressSpace.size; + lowerAddress = chunkList.back().address + chunkList.back().size; + } + + u64 size = upperAddress - lowerAddress; + + return DescriptorPack{ + .chunk = { + .address = lowerAddress, + .size = size, + .state = memory::states::Unmapped + }, + .block = { + .address = lowerAddress, + .size = size, + } + }; + } + return std::nullopt; } diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 306d8e0e..14c9cbdf 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -312,7 +312,8 @@ namespace skyline { friend void svc::MapMemory(skyline::DeviceState &state); - memory::Region base{}; //!< The Region object for the entire address space + memory::Region addressSpace{}; //!< The Region object for the entire address space + memory::Region base{}; //!< The Region object for the entire address space accessible to the application memory::Region code{}; //!< The Region object for the code memory region memory::Region alias{}; //!< The Region object for the alias memory region memory::Region heap{}; //!< The Region object for the heap memory region @@ -323,9 +324,10 @@ namespace skyline { /** * @param address The address to query in the memory map + * @param requireMapped This specifies if only mapped regions should be returned otherwise unmapped but valid regions will also be returned * @return A DescriptorPack retrieved from the memory map */ - std::optional Get(u64 address); + std::optional Get(u64 address, bool requireMapped = true); /** * @brief The total amount of space in bytes occupied by all memory mappings diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 752d21e2..b43c7a57 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -180,7 +180,7 @@ namespace skyline::kernel::svc { memory::MemoryInfo memInfo{}; auto address = state.ctx->registers.x2; - auto descriptor = state.os->memory.Get(address); + auto descriptor = state.os->memory.Get(address, false); if (descriptor) { memInfo = { @@ -195,16 +195,15 @@ namespace skyline::kernel::svc { state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", memInfo.address, memInfo.size, memInfo.type, static_cast(descriptor->block.attributes.isUncached), descriptor->block.permission.r ? "R" : "-", descriptor->block.permission.w ? "W" : "-", descriptor->block.permission.x ? "X" : "-"); } else { - auto region = state.os->memory.base; - auto baseEnd = region.address + region.size; + auto addressSpaceEnd = state.os->memory.addressSpace.address + state.os->memory.addressSpace.size; memInfo = { - .address = region.address, - .size = ~baseEnd + 1, - .type = static_cast(memory::MemoryType::Unmapped), + .address = addressSpaceEnd, + .size = ~addressSpaceEnd + 1, + .type = static_cast(memory::MemoryType::Reserved), }; - state.logger->Debug("svcQueryMemory: Cannot find block of address: 0x{:X}", address); + state.logger->Debug("svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X}", address); } state.process->WriteMemory(memInfo, state.ctx->registers.x0);