mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 08:35:29 +03:00
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.
This commit is contained in:
parent
670a80d2c4
commit
f1a28f7a1c
@ -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<DescriptorPack> MemoryManager::Get(u64 address) {
|
||||
std::optional<DescriptorPack> 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;
|
||||
}
|
||||
|
||||
|
@ -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<DescriptorPack> Get(u64 address);
|
||||
std::optional<DescriptorPack> Get(u64 address, bool requireMapped = true);
|
||||
|
||||
/**
|
||||
* @brief The total amount of space in bytes occupied by all memory mappings
|
||||
|
@ -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<bool>(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<u32>(memory::MemoryType::Unmapped),
|
||||
.address = addressSpaceEnd,
|
||||
.size = ~addressSpaceEnd + 1,
|
||||
.type = static_cast<u32>(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);
|
||||
|
Loading…
Reference in New Issue
Block a user