mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 08:11:48 +01:00
Support mirrors of multiple non-contiguous memory regions
`CreateMirror` is limited to creating a mirror of a single contiguous region which does not work when creating a contiguous mirror of multiple non-contiguous regions. To support this functionality, `CreateMirrors` which expects a list of page-aligned regions and maps them into a contiguous mirror.
This commit is contained in:
parent
e35ab6d1e0
commit
577a67babd
@ -156,6 +156,38 @@ namespace skyline::kernel {
|
||||
return span<u8>{reinterpret_cast<u8 *>(mirror), size};
|
||||
}
|
||||
|
||||
span<u8> MemoryManager::CreateMirrors(const std::vector<span<u8>> ®ions) {
|
||||
size_t totalSize{};
|
||||
for (const auto ®ion : regions)
|
||||
totalSize += region.size();
|
||||
|
||||
auto mirrorBase{mmap(nullptr, totalSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)}; // Reserve address space for all mirrors
|
||||
if (mirrorBase == MAP_FAILED)
|
||||
throw exception("Failed to create mirror base: {} (0x{:X} bytes)", strerror(errno), totalSize);
|
||||
|
||||
size_t mirrorOffset{};
|
||||
for (const auto ®ion : regions) {
|
||||
auto address{reinterpret_cast<u64>(region.data())};
|
||||
if (address < base.address || address + region.size() > base.address + base.size)
|
||||
throw exception("Mapping is outside of VMM base: 0x{:X} - 0x{:X}", address, address + region.size());
|
||||
|
||||
size_t offset{address - base.address};
|
||||
if (!util::IsPageAligned(offset) || !util::IsPageAligned(region.size()))
|
||||
throw exception("Mapping is not aligned to a page: 0x{:X}-0x{:X} (0x{:X})", address, address + region.size(), offset);
|
||||
|
||||
auto mirror{mmap(reinterpret_cast<u8 *>(mirrorBase) + mirrorOffset, region.size(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED, memoryFd, static_cast<off_t>(offset))};
|
||||
if (mirror == MAP_FAILED)
|
||||
throw exception("Failed to create mirror mapping at 0x{:X}-0x{:X} (0x{:X}): {}", address, address + region.size(), offset, strerror(errno));
|
||||
|
||||
mirrorOffset += region.size();
|
||||
}
|
||||
|
||||
if (mirrorOffset != totalSize)
|
||||
throw exception("Mirror size mismatch: 0x{:X} != 0x{:X}", mirrorOffset, totalSize);
|
||||
|
||||
return span<u8>{reinterpret_cast<u8 *>(mirrorBase), totalSize};
|
||||
}
|
||||
|
||||
void MemoryManager::InsertChunk(const ChunkDescriptor &chunk) {
|
||||
std::unique_lock lock(mutex);
|
||||
|
||||
|
@ -248,6 +248,15 @@ namespace skyline {
|
||||
*/
|
||||
span<u8> CreateMirror(u8* pointer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Mirrors multiple page-aligned mapping in the guest address space to the host address space
|
||||
* @param totalSize The total size of all the regions to be mirrored combined
|
||||
* @return A span to the host address space mirror mapped as RWX, unmapping it is the responsibility of the caller
|
||||
* @note The supplied mapping **must** be page-aligned and inside the guest address space
|
||||
* @note If a single mapping is mirrored, it is recommended to use CreateMirror instead
|
||||
*/
|
||||
span<u8> CreateMirrors(const std::vector<span<u8>>& regions);
|
||||
|
||||
void InsertChunk(const ChunkDescriptor &chunk);
|
||||
|
||||
std::optional<ChunkDescriptor> Get(void *ptr);
|
||||
|
Loading…
Reference in New Issue
Block a user