graphics: upload sparse PRT image backing

This commit is contained in:
nmzik
2026-08-16 04:52:18 +02:00
parent 989477efad
commit 547b9b96cc
5 changed files with 147 additions and 4 deletions
+2 -1
View File
@@ -621,7 +621,8 @@ ImageBufferSource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t siz
}
auto [staging, stage_offset] = m_staging_buffer.Map(size, 16);
if (staging == nullptr || !Libs::LibKernel::Memory::TryReadBacking(vaddr, staging, size)) {
if (staging == nullptr || (!Libs::LibKernel::Memory::TryReadBacking(vaddr, staging, size) &&
!Libs::LibKernel::Memory::TryReadPrtBacking(vaddr, staging, size))) {
EXIT("BufferCache: failed to read mapped guest image backing\n");
}
m_staging_buffer.Commit();
+24 -3
View File
@@ -921,18 +921,39 @@ constexpr uint64_t PRT_APERTURE_END = 0xfc00000000ull;
static std::array<PrtAperture, PRT_APERTURE_MAX_INDEX + 1> g_prt_apertures {};
static Common::Mutex g_prt_aperture_mutex;
static bool IsInPrtAperture(uint64_t address) {
static bool IsInPrtAperture(uint64_t address, uint64_t size = 1) {
if (size == 0 || UINT64_MAX - address < size) {
return false;
}
Common::LockGuard lock(g_prt_aperture_mutex);
for (const auto& aperture: g_prt_apertures) {
if (address >= aperture.address && address < aperture.address + aperture.size) {
return true;
if (address >= aperture.address) {
const auto offset = address - aperture.address;
if (offset < aperture.size && size <= aperture.size - offset) {
return true;
}
}
}
return false;
}
bool TryReadPrtBacking(uint64_t vaddr, void* data, uint64_t size) {
std::vector<VirtualRanges::Range> ranges;
if (g_guest_address_space == nullptr || g_virtual_ranges == nullptr ||
!IsInPrtAperture(vaddr, size) || !g_virtual_ranges->QuerySpan(vaddr, size, &ranges)) {
return false;
}
if (std::any_of(ranges.begin(), ranges.end(), [](const auto& range) {
return !IsReservedRangeType(range.type) &&
!g_guest_address_space->BackingContains(range.start, range.size);
})) {
return false;
}
return g_guest_address_space->TryReadSparseBacking(vaddr, data, size);
}
static bool SelfTestSub64SharedPlaceholderAlias() {
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
constexpr uint64_t PageSize = 0x4000;
+1
View File
@@ -109,6 +109,7 @@ void RegisterCallbacks(callback_func_t alloc_func, callback_fu
void SetFlexibleMemorySize(uint64_t size);
bool TryWriteBacking(uint64_t vaddr, const void* data, uint64_t size);
bool TryReadBacking(uint64_t vaddr, void* data, uint64_t size);
bool TryReadPrtBacking(uint64_t vaddr, void* data, uint64_t size);
[[nodiscard]] uint64_t ClampRangeSize(uint64_t vaddr, uint64_t size);
void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept;
void InvalidateMemory(uint64_t vaddr, uint64_t size);
+41
View File
@@ -188,6 +188,43 @@ public:
});
}
bool TryReadSparseBacking(uint64_t vaddr, void* data, uint64_t size) {
if (!IsAvailable() || data == nullptr || size == 0 || UINT64_MAX - vaddr < size) {
return false;
}
std::lock_guard lock(m_mutex);
const auto end = vaddr + size;
auto first = m_maps.lower_bound(vaddr);
if (first != m_maps.begin()) {
auto previous = std::prev(first);
if (previous->second.vaddr + previous->second.size > vaddr) {
first = previous;
}
}
for (auto mapping = first; mapping != m_maps.end() && mapping->second.vaddr < end;
++mapping) {
const auto& entry = mapping->second;
const auto start = std::max(vaddr, entry.vaddr);
const auto bytes = std::min(end, entry.vaddr + entry.size) - start;
if (!RangeOk(entry.backing_offset + start - entry.vaddr, bytes)) {
return false;
}
}
auto* destination = static_cast<uint8_t*>(data);
std::memset(destination, 0, size);
for (auto mapping = first; mapping != m_maps.end() && mapping->second.vaddr < end;
++mapping) {
const auto& entry = mapping->second;
const auto start = std::max(vaddr, entry.vaddr);
const auto bytes = std::min(end, entry.vaddr + entry.size) - start;
const auto offset = entry.backing_offset + start - entry.vaddr;
std::memcpy(destination + start - vaddr, m_backing_base + offset, bytes);
}
return true;
}
bool MapExistingPlaceholderFixed(uint64_t vaddr, uint64_t size, uint64_t backing_offset,
VirtualMemory::Mode mode,
FailureReason* failure_reason = nullptr) {
@@ -694,6 +731,10 @@ public:
return m_backing->TryReadBacking(vaddr, data, size);
}
bool TryReadSparseBacking(uint64_t vaddr, void* data, uint64_t size) {
return m_backing->TryReadSparseBacking(vaddr, data, size);
}
bool BackingContains(uint64_t vaddr, uint64_t size) { return m_backing->Contains(vaddr, size); }
bool Protect(uint64_t vaddr, uint64_t size, VirtualMemory::Mode mode) {