mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
Fix vertex buffer ranges crossing memory mappings
This commit is contained in:
@@ -18,15 +18,16 @@
|
|||||||
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
||||||
#include "graphics/host_gpu/renderer/pipeline/descriptorCache.h"
|
#include "graphics/host_gpu/renderer/pipeline/descriptorCache.h"
|
||||||
#include "graphics/host_gpu/renderer/pipeline/pipelineCache.h"
|
#include "graphics/host_gpu/renderer/pipeline/pipelineCache.h"
|
||||||
#include "graphics/host_gpu/renderer/render.h"
|
|
||||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
|
||||||
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
||||||
#include "graphics/host_gpu/renderer/pipeline/shaderSubgroup.h"
|
#include "graphics/host_gpu/renderer/pipeline/shaderSubgroup.h"
|
||||||
|
#include "graphics/host_gpu/renderer/render.h"
|
||||||
|
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||||
#include "graphics/host_gpu/vulkanCommon.h"
|
#include "graphics/host_gpu/vulkanCommon.h"
|
||||||
#include "graphics/shader/recompiler/ir/ResourceMaterialization.h"
|
#include "graphics/shader/recompiler/ir/ResourceMaterialization.h"
|
||||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||||
#include "graphics/shader/shader.h"
|
#include "graphics/shader/shader.h"
|
||||||
#include "kernel/eventQueue.h"
|
#include "kernel/eventQueue.h"
|
||||||
|
#include "kernel/memory.h"
|
||||||
#include "kernel/pthread.h"
|
#include "kernel/pthread.h"
|
||||||
#include "libs/errno.h"
|
#include "libs/errno.h"
|
||||||
|
|
||||||
@@ -221,8 +222,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
|
|||||||
LogMrtState(draw_name, buffer, ps_input_info);
|
LogMrtState(draw_name, buffer, ps_input_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LogDrawInputState(const RenderCommandBuffer& buffer,
|
static void LogDrawInputState(const RenderCommandBuffer& buffer, const RenderColorInfo& color,
|
||||||
const RenderColorInfo& color,
|
|
||||||
const ShaderVertexInputInfo& vs_input_info,
|
const ShaderVertexInputInfo& vs_input_info,
|
||||||
uint32_t index_type_and_size, uint32_t index_count,
|
uint32_t index_type_and_size, uint32_t index_count,
|
||||||
const void* index_addr) {
|
const void* index_addr) {
|
||||||
@@ -512,8 +512,7 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
auto& target = colors[i];
|
auto& target = colors[i];
|
||||||
EXIT_IF(!target.image_id);
|
EXIT_IF(!target.image_id);
|
||||||
const auto old_image = cache.ResolveOwner(target.image_id);
|
const auto old_image = cache.ResolveOwner(target.image_id);
|
||||||
if (old_image == nullptr ||
|
if (old_image == nullptr || (!old_image->registered && !old_image->info.data.Empty()) ||
|
||||||
(!old_image->registered && !old_image->info.data.Empty()) ||
|
|
||||||
old_image->binding.needs_rebind) {
|
old_image->binding.needs_rebind) {
|
||||||
if (old_image != nullptr) {
|
if (old_image != nullptr) {
|
||||||
old_image->binding = {};
|
old_image->binding = {};
|
||||||
@@ -531,8 +530,7 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
attachment_samples, target.samples);
|
attachment_samples, target.samples);
|
||||||
}
|
}
|
||||||
const auto& view = target.desc.view_info;
|
const auto& view = target.desc.view_info;
|
||||||
const auto layout =
|
const auto layout = image.binding.is_bound ? vk::ImageLayout::eGeneral
|
||||||
image.binding.is_bound ? vk::ImageLayout::eGeneral
|
|
||||||
: vk::ImageLayout::eColorAttachmentOptimal;
|
: vk::ImageLayout::eColorAttachmentOptimal;
|
||||||
image.Transit(layout,
|
image.Transit(layout,
|
||||||
vk::AccessFlagBits2::eColorAttachmentRead |
|
vk::AccessFlagBits2::eColorAttachmentRead |
|
||||||
@@ -561,8 +559,7 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
depth.depth_meta_clear_enable =
|
depth.depth_meta_clear_enable =
|
||||||
depth.htile &&
|
depth.htile &&
|
||||||
cache.IsMetaCleared(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer);
|
cache.IsMetaCleared(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer);
|
||||||
depth.depth_load_clear_enable =
|
depth.depth_load_clear_enable = depth.depth_clear_enable || depth.depth_meta_clear_enable;
|
||||||
depth.depth_clear_enable || depth.depth_meta_clear_enable;
|
|
||||||
if (depth.depth_meta_clear_enable &&
|
if (depth.depth_meta_clear_enable &&
|
||||||
!cache.TouchMeta(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer, false)) {
|
!cache.TouchMeta(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer, false)) {
|
||||||
EXIT("failed to consume HTile clear state\n");
|
EXIT("failed to consume HTile clear state\n");
|
||||||
@@ -572,8 +569,8 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
if (attachment_samples == 0) {
|
if (attachment_samples == 0) {
|
||||||
attachment_samples = depth.samples;
|
attachment_samples = depth.samples;
|
||||||
} else if (attachment_samples != depth.samples) {
|
} else if (attachment_samples != depth.samples) {
|
||||||
EXIT("mixed color/depth sample counts are unsupported: %u and %u\n",
|
EXIT("mixed color/depth sample counts are unsupported: %u and %u\n", attachment_samples,
|
||||||
attachment_samples, depth.samples);
|
depth.samples);
|
||||||
}
|
}
|
||||||
const auto layout = depth_attachment_layout(depth);
|
const auto layout = depth_attachment_layout(depth);
|
||||||
const auto writes = depth.AttachmentWriteAspects();
|
const auto writes = depth.AttachmentWriteAspects();
|
||||||
@@ -595,11 +592,9 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
attachment.image_layout = layout;
|
attachment.image_layout = layout;
|
||||||
attachment.clear_value[0] = std::bit_cast<uint32_t>(depth.depth_clear_value);
|
attachment.clear_value[0] = std::bit_cast<uint32_t>(depth.depth_clear_value);
|
||||||
attachment.clear_value[1] = depth.stencil_clear_value;
|
attachment.clear_value[1] = depth.stencil_clear_value;
|
||||||
attachment.has_depth =
|
attachment.has_depth = static_cast<bool>(aspects & vk::ImageAspectFlagBits::eDepth);
|
||||||
static_cast<bool>(aspects & vk::ImageAspectFlagBits::eDepth);
|
|
||||||
attachment.depth_clear = depth.depth_load_clear_enable;
|
attachment.depth_clear = depth.depth_load_clear_enable;
|
||||||
attachment.has_stencil =
|
attachment.has_stencil = static_cast<bool>(aspects & vk::ImageAspectFlagBits::eStencil);
|
||||||
static_cast<bool>(aspects & vk::ImageAspectFlagBits::eStencil);
|
|
||||||
attachment.stencil_clear = depth.stencil_clear_enable;
|
attachment.stencil_clear = depth.stencil_clear_enable;
|
||||||
}
|
}
|
||||||
if (attachment_samples == 0 ||
|
if (attachment_samples == 0 ||
|
||||||
@@ -685,6 +680,85 @@ static uint64_t VertexBufferDescriptorSize(const ShaderVertexInputBuffer& buffer
|
|||||||
: buffer.num_records);
|
: buffer.num_records);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VertexBufferRange {
|
||||||
|
uint64_t base_address = 0;
|
||||||
|
uint64_t requested_end = 0;
|
||||||
|
uint64_t acquired_end = 0;
|
||||||
|
BufferBinding binding;
|
||||||
|
|
||||||
|
[[nodiscard]] uint64_t RequestedSize() const { return requested_end - base_address; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<BufferBinding> AcquireVertexBuffers(RenderCommandBuffer& buffer,
|
||||||
|
const ShaderVertexInputInfo& vs_input_info) {
|
||||||
|
// Collect the non-empty guest vertex ranges.
|
||||||
|
std::vector<VertexBufferRange> ranges;
|
||||||
|
ranges.reserve(vs_input_info.buffers_num);
|
||||||
|
for (int i = 0; i < vs_input_info.buffers_num; i++) {
|
||||||
|
const auto& vertex = vs_input_info.buffers[i];
|
||||||
|
const auto size = VertexBufferDescriptorSize(vertex);
|
||||||
|
if (size == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (vertex.addr == 0 || size > UINT64_MAX - vertex.addr) {
|
||||||
|
EXIT("invalid vertex buffer range: addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
|
||||||
|
vertex.addr, size);
|
||||||
|
}
|
||||||
|
ranges.push_back({vertex.addr, vertex.addr + size});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ranges::sort(ranges, [](const VertexBufferRange& left, const VertexBufferRange& right) {
|
||||||
|
return left.base_address < right.base_address;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Merge overlapping or touching ranges before acquiring host buffers.
|
||||||
|
std::vector<VertexBufferRange> merged_ranges;
|
||||||
|
merged_ranges.reserve(ranges.size());
|
||||||
|
for (const auto& range: ranges) {
|
||||||
|
if (!merged_ranges.empty() && merged_ranges.back().requested_end >= range.base_address) {
|
||||||
|
merged_ranges.back().requested_end =
|
||||||
|
std::max(merged_ranges.back().requested_end, range.requested_end);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
merged_ranges.push_back(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& cache = buffer.GetContext().GetBufferCache();
|
||||||
|
for (auto& range: merged_ranges) {
|
||||||
|
// PPSA20298
|
||||||
|
const auto size =
|
||||||
|
Libs::LibKernel::Memory::ClampRangeSize(range.base_address, range.RequestedSize());
|
||||||
|
range.acquired_end = range.base_address + size;
|
||||||
|
range.binding = cache.ObtainBuffer(buffer, range.base_address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild slot bindings, offsetting non-empty slots into their acquired merged range.
|
||||||
|
std::vector<BufferBinding> bindings;
|
||||||
|
bindings.reserve(vs_input_info.buffers_num);
|
||||||
|
for (int i = 0; i < vs_input_info.buffers_num; i++) {
|
||||||
|
const auto& vertex = vs_input_info.buffers[i];
|
||||||
|
const auto size = VertexBufferDescriptorSize(vertex);
|
||||||
|
if (size == 0) {
|
||||||
|
auto owner = cache.ObtainNullBuffer();
|
||||||
|
bindings.push_back({owner, owner->Handle(), 0});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto range = std::ranges::find_if(merged_ranges, [&](const VertexBufferRange& value) {
|
||||||
|
return vertex.addr >= value.base_address && vertex.addr < value.acquired_end;
|
||||||
|
});
|
||||||
|
if (range == merged_ranges.end()) {
|
||||||
|
EXIT("vertex buffer address is outside the acquired range: addr=0x%016" PRIx64 "\n",
|
||||||
|
vertex.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto binding = range->binding;
|
||||||
|
binding.offset += vertex.addr - range->base_address;
|
||||||
|
bindings.push_back(std::move(binding));
|
||||||
|
}
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
static void SetDrawDebugPhase(RenderCommandBuffer& buffer, uint64_t submit_id,
|
static void SetDrawDebugPhase(RenderCommandBuffer& buffer, uint64_t submit_id,
|
||||||
const DrawCallInfo& draw, uint32_t phase) {
|
const DrawCallInfo& draw, uint32_t phase) {
|
||||||
EXIT_IF(draw.name == nullptr);
|
EXIT_IF(draw.name == nullptr);
|
||||||
@@ -823,37 +897,13 @@ static std::vector<BufferBinding> PrepareVertexBuffers(uint64_t
|
|||||||
(void)submit_id;
|
(void)submit_id;
|
||||||
|
|
||||||
LogDrawPhase(draw.name, "PrepareVertexBuffers");
|
LogDrawPhase(draw.name, "PrepareVertexBuffers");
|
||||||
std::vector<BufferBinding> bindings;
|
return AcquireVertexBuffers(buffer, vs_input_info);
|
||||||
bindings.reserve(vs_input_info.buffers_num);
|
|
||||||
for (int i = 0; i < vs_input_info.buffers_num; i++) {
|
|
||||||
const auto& b = vs_input_info.buffers[i];
|
|
||||||
const auto size = VertexBufferDescriptorSize(b);
|
|
||||||
if (size == 0) {
|
|
||||||
auto owner = buffer.GetContext().GetBufferCache().ObtainNullBuffer();
|
|
||||||
bindings.push_back({owner, owner->Handle(), 0});
|
|
||||||
} else {
|
|
||||||
bindings.push_back(
|
|
||||||
buffer.GetContext().GetBufferCache().ObtainBuffer(buffer, b.addr, size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bindings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RebindVertexBuffers(RenderCommandBuffer& buffer,
|
static void RebindVertexBuffers(RenderCommandBuffer& buffer,
|
||||||
const ShaderVertexInputInfo& vs_input_info,
|
const ShaderVertexInputInfo& vs_input_info,
|
||||||
std::vector<BufferBinding>& bindings) {
|
std::vector<BufferBinding>& bindings) {
|
||||||
EXIT_IF(bindings.size() != static_cast<size_t>(vs_input_info.buffers_num));
|
bindings = AcquireVertexBuffers(buffer, vs_input_info);
|
||||||
for (int i = 0; i < vs_input_info.buffers_num; i++) {
|
|
||||||
const auto& vertex = vs_input_info.buffers[i];
|
|
||||||
const auto size = VertexBufferDescriptorSize(vertex);
|
|
||||||
if (size == 0) {
|
|
||||||
auto owner = buffer.GetContext().GetBufferCache().ObtainNullBuffer();
|
|
||||||
bindings[i] = {owner, owner->Handle(), 0};
|
|
||||||
} else {
|
|
||||||
bindings[i] =
|
|
||||||
buffer.GetContext().GetBufferCache().ObtainBuffer(buffer, vertex.addr, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PreparedIndexBuffer PrepareIndexBuffer(RenderCommandBuffer& buffer,
|
static PreparedIndexBuffer PrepareIndexBuffer(RenderCommandBuffer& buffer,
|
||||||
@@ -1228,8 +1278,7 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||||
void RenderExecutor::DrawAuto(uint64_t submit_id, RenderCommandBuffer& buffer,
|
void RenderExecutor::DrawAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count,
|
||||||
uint32_t index_count,
|
|
||||||
uint32_t flags, uint32_t render_target_slice_offset,
|
uint32_t flags, uint32_t render_target_slice_offset,
|
||||||
uint32_t instance_count, uint32_t first_vertex,
|
uint32_t instance_count, uint32_t first_vertex,
|
||||||
uint32_t first_instance) {
|
uint32_t first_instance) {
|
||||||
@@ -1290,7 +1339,8 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, RenderCommandBuffer& buffer,
|
|||||||
instance_count, first_instance};
|
instance_count, first_instance};
|
||||||
|
|
||||||
DrawRenderState state {};
|
DrawRenderState state {};
|
||||||
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false, state)) {
|
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false,
|
||||||
|
state)) {
|
||||||
ResetBindings();
|
ResetBindings();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1369,8 +1419,7 @@ bool RenderExecutor::ResolveColorTargets(uint64_t submit_id, RenderCommandBuffer
|
|||||||
cache.MarkGpuWritten(dst.image_id);
|
cache.MarkGpuWritten(dst.image_id);
|
||||||
auto& source = cache.GetImage(src.image_id);
|
auto& source = cache.GetImage(src.image_id);
|
||||||
auto& destination = cache.GetImage(dst.image_id);
|
auto& destination = cache.GetImage(dst.image_id);
|
||||||
destination.Resolve(source,
|
destination.Resolve(source, {src.base_mip_level, 1, src.base_array_layer, 1},
|
||||||
{src.base_mip_level, 1, src.base_array_layer, 1},
|
|
||||||
{dst.base_mip_level, 1, dst.base_array_layer, 1});
|
{dst.base_mip_level, 1, dst.base_array_layer, 1});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -528,6 +528,42 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t ClampRangeSize(uint64_t virtual_addr, uint64_t size) {
|
||||||
|
Common::LockGuard lock(m_mutex);
|
||||||
|
|
||||||
|
if (virtual_addr == 0 || size == 0 || size > UINT64_MAX - virtual_addr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vma = std::upper_bound(
|
||||||
|
m_ranges.begin(), m_ranges.end(), virtual_addr,
|
||||||
|
[](uint64_t value, const Range& range) { return value < range.start; });
|
||||||
|
if (vma == m_ranges.begin()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
--vma;
|
||||||
|
|
||||||
|
const auto vma_end = End(vma->start, vma->size);
|
||||||
|
if (virtual_addr < vma->start || virtual_addr >= vma_end ||
|
||||||
|
!IsCommittedRangeType(vma->type)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t clamped_size = std::min(size, vma_end - virtual_addr);
|
||||||
|
uint64_t expected = virtual_addr + clamped_size;
|
||||||
|
++vma;
|
||||||
|
|
||||||
|
while (vma != m_ranges.end() && vma->start == expected && IsCommittedRangeType(vma->type) &&
|
||||||
|
clamped_size < size) {
|
||||||
|
const auto chunk = std::min(size - clamped_size, vma->size);
|
||||||
|
clamped_size += chunk;
|
||||||
|
expected += chunk;
|
||||||
|
++vma;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clamped_size;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t CountPageTableEntries(bool gpu) {
|
uint64_t CountPageTableEntries(bool gpu) {
|
||||||
Common::LockGuard lock(m_mutex);
|
Common::LockGuard lock(m_mutex);
|
||||||
|
|
||||||
@@ -884,6 +920,23 @@ bool TryReadBacking(uint64_t vaddr, void* data, uint64_t size) {
|
|||||||
g_direct_memory_backing->TryReadBacking(vaddr, data, size);
|
g_direct_memory_backing->TryReadBacking(vaddr, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t ClampRangeSize(uint64_t vaddr, uint64_t size) {
|
||||||
|
EXIT_IF(g_virtual_ranges == nullptr);
|
||||||
|
|
||||||
|
const auto clamped_size = g_virtual_ranges->ClampRangeSize(vaddr, size);
|
||||||
|
if (clamped_size == 0) {
|
||||||
|
EXIT("Memory: attempted to access invalid address 0x%016" PRIx64 " with size 0x%016" PRIx64
|
||||||
|
"\n",
|
||||||
|
vaddr, size);
|
||||||
|
}
|
||||||
|
if (clamped_size != size) {
|
||||||
|
LOGF("Memory: clamped buffer range addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
||||||
|
" to 0x%016" PRIx64 "\n",
|
||||||
|
vaddr, size, clamped_size);
|
||||||
|
}
|
||||||
|
return clamped_size;
|
||||||
|
}
|
||||||
|
|
||||||
void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept {
|
void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept {
|
||||||
if (!TryWriteBacking(vaddr, data, size)) {
|
if (!TryWriteBacking(vaddr, data, size)) {
|
||||||
EXIT("Memory: required direct-backing write failed, addr=0x%016" PRIx64
|
EXIT("Memory: required direct-backing write failed, addr=0x%016" PRIx64
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ void RegisterCallbacks(callback_func_t alloc_func, callback_func_t
|
|||||||
void SetFlexibleMemorySize(uint64_t size);
|
void SetFlexibleMemorySize(uint64_t size);
|
||||||
bool TryWriteBacking(uint64_t vaddr, const void* data, 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 TryReadBacking(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 WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept;
|
||||||
void InvalidateMemory(uint64_t vaddr, uint64_t size);
|
void InvalidateMemory(uint64_t vaddr, uint64_t size);
|
||||||
void InstallGpuResources(Graphics::GpuResourceManager* resources) noexcept;
|
void InstallGpuResources(Graphics::GpuResourceManager* resources) noexcept;
|
||||||
|
|||||||
@@ -405,6 +405,10 @@ void TestDirectMapQueryOffsetAndPartialMunmap() {
|
|||||||
"TryReadBacking should reject a range crossing an unmapped span");
|
"TryReadBacking should reject a range crossing an unmapped span");
|
||||||
Check(test, rejected_read == transaction_sentinel,
|
Check(test, rejected_read == transaction_sentinel,
|
||||||
"failed backing reads must not modify a destination prefix");
|
"failed backing reads must not modify a destination prefix");
|
||||||
|
Check(test,
|
||||||
|
Libs::LibKernel::Memory::ClampRangeSize(base + SceKernelPageSize - 0xf30, 0x1560) ==
|
||||||
|
0xf30,
|
||||||
|
"ClampRangeSize did not stop at an unmapped span");
|
||||||
|
|
||||||
info = Query(test, base + SceKernelPageSize, SceKernelVqFindNext);
|
info = Query(test, base + SceKernelPageSize, SceKernelVqFindNext);
|
||||||
ExpectRange(test, info, base + SceKernelPageSize * 2, base + SceKernelPageSize * 4,
|
ExpectRange(test, info, base + SceKernelPageSize * 2, base + SceKernelPageSize * 4,
|
||||||
@@ -473,6 +477,11 @@ void TestMunmapAcrossAdjacentFlexibleMappings() {
|
|||||||
&right, SceKernelPageSize, SceKernelProtCpuRw, SceKernelMapFixed, "adjacent_right"),
|
&right, SceKernelPageSize, SceKernelProtCpuRw, SceKernelMapFixed, "adjacent_right"),
|
||||||
"KernelMapNamedFlexibleMemory(right)");
|
"KernelMapNamedFlexibleMemory(right)");
|
||||||
|
|
||||||
|
Check(test,
|
||||||
|
Libs::LibKernel::Memory::ClampRangeSize(base + SceKernelPageSize - 0x100, 0x200) ==
|
||||||
|
0x200,
|
||||||
|
"ClampRangeSize did not cross adjacent committed mappings");
|
||||||
|
|
||||||
CheckOk(test, Libs::LibKernel::Memory::KernelMunmap(base, SceKernelPageSize * 2),
|
CheckOk(test, Libs::LibKernel::Memory::KernelMunmap(base, SceKernelPageSize * 2),
|
||||||
"KernelMunmap(adjacent mappings)");
|
"KernelMunmap(adjacent mappings)");
|
||||||
Check(test, AvailableFlexibleMemory(test) == baseline,
|
Check(test, AvailableFlexibleMemory(test) == baseline,
|
||||||
|
|||||||
Reference in New Issue
Block a user