mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-23 18:45:36 +00:00
Sync page manager protections
This commit is contained in:
parent
4c279f64c7
commit
71d5d27ab2
@ -57,12 +57,6 @@ struct PageManager::Impl {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateProtectRange {
|
|
||||||
VAddr addr;
|
|
||||||
u64 size;
|
|
||||||
Core::MemoryPermission perms;
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr size_t ADDRESS_BITS = 40;
|
static constexpr size_t ADDRESS_BITS = 40;
|
||||||
static constexpr size_t NUM_ADDRESS_PAGES = 1ULL << (40 - PAGE_BITS);
|
static constexpr size_t NUM_ADDRESS_PAGES = 1ULL << (40 - PAGE_BITS);
|
||||||
inline static Vulkan::Rasterizer* rasterizer;
|
inline static Vulkan::Rasterizer* rasterizer;
|
||||||
@ -195,69 +189,60 @@ struct PageManager::Impl {
|
|||||||
template <bool track>
|
template <bool track>
|
||||||
void UpdatePageWatchers(VAddr addr, u64 size) {
|
void UpdatePageWatchers(VAddr addr, u64 size) {
|
||||||
RENDERER_TRACE;
|
RENDERER_TRACE;
|
||||||
boost::container::small_vector<UpdateProtectRange, 16> update_ranges;
|
|
||||||
{
|
size_t page = addr >> PAGE_BITS;
|
||||||
std::scoped_lock lk(lock);
|
auto perms = cached_pages[page].Perm();
|
||||||
|
u64 range_begin = 0;
|
||||||
|
u64 range_bytes = 0;
|
||||||
|
|
||||||
|
const auto release_pending = [&] {
|
||||||
|
if (range_bytes > 0) {
|
||||||
|
RENDERER_TRACE;
|
||||||
|
// Perform pending (un)protect action
|
||||||
|
Protect(range_begin << PAGE_BITS, range_bytes, perms);
|
||||||
|
range_bytes = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::scoped_lock lk(lock);
|
||||||
|
|
||||||
size_t page = addr >> PAGE_BITS;
|
// Iterate requested pages
|
||||||
auto perms = cached_pages[page].Perm();
|
const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
|
||||||
u64 range_begin = 0;
|
const u64 aligned_addr = page << PAGE_BITS;
|
||||||
u64 range_bytes = 0;
|
const u64 aligned_end = page_end << PAGE_BITS;
|
||||||
|
ASSERT_MSG(rasterizer->IsMapped(aligned_addr, aligned_end - aligned_addr),
|
||||||
|
"Attempted to track non-GPU memory at address {:#x}, size {:#x}.",
|
||||||
|
aligned_addr, aligned_end - aligned_addr);
|
||||||
|
|
||||||
const auto release_pending = [&] {
|
for (; page != page_end; ++page) {
|
||||||
if (range_bytes > 0) {
|
PageState& state = cached_pages[page];
|
||||||
RENDERER_TRACE;
|
|
||||||
// Add pending (un)protect action
|
|
||||||
update_ranges.push_back({range_begin << PAGE_BITS, range_bytes, perms});
|
|
||||||
range_bytes = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Iterate requested pages
|
// Apply the change to the page state
|
||||||
const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
|
const u8 new_count = state.AddDelta<track ? 1 : -1>();
|
||||||
const u64 aligned_addr = page << PAGE_BITS;
|
|
||||||
const u64 aligned_end = page_end << PAGE_BITS;
|
|
||||||
ASSERT_MSG(rasterizer->IsMapped(aligned_addr, aligned_end - aligned_addr),
|
|
||||||
"Attempted to track non-GPU memory at address {:#x}, size {:#x}.",
|
|
||||||
aligned_addr, aligned_end - aligned_addr);
|
|
||||||
|
|
||||||
for (; page != page_end; ++page) {
|
if (auto new_perms = state.Perm(); new_perms != perms) [[unlikely]] {
|
||||||
PageState& state = cached_pages[page];
|
// If the protection changed add pending (un)protect action
|
||||||
|
release_pending();
|
||||||
// Apply the change to the page state
|
perms = new_perms;
|
||||||
const u8 new_count = state.AddDelta<track ? 1 : -1>();
|
} else if (range_bytes != 0) {
|
||||||
|
// If the protection did not change, extend the current range
|
||||||
if (auto new_perms = state.Perm(); new_perms != perms) [[unlikely]] {
|
range_bytes += PAGE_SIZE;
|
||||||
// If the protection changed add pending (un)protect action
|
|
||||||
release_pending();
|
|
||||||
perms = new_perms;
|
|
||||||
} else if (range_bytes != 0) {
|
|
||||||
// If the protection did not change, extend the current range
|
|
||||||
range_bytes += PAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only start a new range if the page must be (un)protected
|
|
||||||
if (range_bytes == 0 && ((new_count == 0 && !track) || (new_count == 1 && track))) {
|
|
||||||
range_begin = page;
|
|
||||||
range_bytes = PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add pending (un)protect action
|
// Only start a new range if the page must be (un)protected
|
||||||
release_pending();
|
if (range_bytes == 0 && ((new_count == 0 && !track) || (new_count == 1 && track))) {
|
||||||
|
range_begin = page;
|
||||||
|
range_bytes = PAGE_SIZE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush deferred protects
|
// Add pending (un)protect action
|
||||||
for (const auto& range : update_ranges) {
|
release_pending();
|
||||||
Protect(range.addr, range.size, range.perms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool track>
|
template <bool track>
|
||||||
void UpdatePageWatchersMasked(VAddr base_addr, RegionBits& mask) {
|
void UpdatePageWatchersMasked(VAddr base_addr, RegionBits& mask) {
|
||||||
RENDERER_TRACE;
|
RENDERER_TRACE;
|
||||||
boost::container::small_vector<UpdateProtectRange, 16> update_ranges;
|
|
||||||
|
|
||||||
auto start_range = mask.FirstRange();
|
auto start_range = mask.FirstRange();
|
||||||
auto end_range = mask.LastRange();
|
auto end_range = mask.LastRange();
|
||||||
|
|
||||||
@ -269,61 +254,55 @@ struct PageManager::Impl {
|
|||||||
UpdatePageWatchers<track>(start_addr, size);
|
UpdatePageWatchers<track>(start_addr, size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t base_page = (base_addr >> PAGE_BITS);
|
||||||
|
auto perms = cached_pages[base_page + start_range.first].Perm();
|
||||||
|
u64 range_begin = 0;
|
||||||
|
u64 range_bytes = 0;
|
||||||
|
|
||||||
|
const auto release_pending = [&] {
|
||||||
|
if (range_bytes > 0) {
|
||||||
|
RENDERER_TRACE;
|
||||||
|
// Perform pending (un)protect action
|
||||||
|
Protect((range_begin << PAGE_BITS), range_bytes, perms);
|
||||||
|
range_bytes = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::scoped_lock lk(lock);
|
||||||
|
|
||||||
{
|
// Iterate pages
|
||||||
std::scoped_lock lk(lock);
|
for (size_t page = start_range.first; page < end_range.second; ++page) {
|
||||||
|
PageState& state = cached_pages[base_page + page];
|
||||||
|
const bool update = mask.Get(page);
|
||||||
|
|
||||||
size_t base_page = (base_addr >> PAGE_BITS);
|
// Apply the change to the page state
|
||||||
auto perms = cached_pages[base_page + start_range.first].Perm();
|
const u8 new_count =
|
||||||
u64 range_begin = 0;
|
update ? state.AddDelta<track ? 1 : -1>() : state.AddDelta<0>();
|
||||||
u64 range_bytes = 0;
|
|
||||||
|
|
||||||
const auto release_pending = [&] {
|
if (auto new_perms = state.Perm(); new_perms != perms) [[unlikely]] {
|
||||||
if (range_bytes > 0) {
|
// If the protection changed add pending (un)protect action
|
||||||
RENDERER_TRACE;
|
release_pending();
|
||||||
// Add pending (un)protect action
|
perms = new_perms;
|
||||||
update_ranges.push_back({range_begin << PAGE_BITS, range_bytes, perms});
|
} else if (range_bytes != 0) {
|
||||||
range_bytes = 0;
|
// If the protection did not change, extend the current range
|
||||||
}
|
range_bytes += PAGE_SIZE;
|
||||||
};
|
|
||||||
|
|
||||||
for (size_t page = start_range.first; page < end_range.second; ++page) {
|
|
||||||
PageState& state = cached_pages[base_page + page];
|
|
||||||
const bool update = mask.Get(page);
|
|
||||||
|
|
||||||
// Apply the change to the page state
|
|
||||||
const u8 new_count =
|
|
||||||
update ? state.AddDelta<track ? 1 : -1>() : state.AddDelta<0>();
|
|
||||||
|
|
||||||
if (auto new_perms = state.Perm(); new_perms != perms) [[unlikely]] {
|
|
||||||
// If the protection changed add pending (un)protect action
|
|
||||||
release_pending();
|
|
||||||
perms = new_perms;
|
|
||||||
} else if (range_bytes != 0) {
|
|
||||||
// If the protection did not change, extend the current range
|
|
||||||
range_bytes += PAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the page is not being updated, skip it
|
|
||||||
if (!update) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only start a new range if the page must be (un)protected
|
|
||||||
if (range_bytes == 0 && ((new_count == 0 && !track) || (new_count == 1 && track))) {
|
|
||||||
range_begin = base_page + page;
|
|
||||||
range_bytes = PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add pending (un)protect action
|
// If the page is not being updated, skip it
|
||||||
release_pending();
|
if (!update) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only start a new range if the page must be (un)protected
|
||||||
|
if (range_bytes == 0 && ((new_count == 0 && !track) || (new_count == 1 && track))) {
|
||||||
|
range_begin = base_page + page;
|
||||||
|
range_bytes = PAGE_SIZE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush deferred protects
|
// Add pending (un)protect action
|
||||||
for (const auto& range : update_ranges) {
|
release_pending();
|
||||||
Protect(range.addr, range.size, range.perms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<PageState, NUM_ADDRESS_PAGES> cached_pages{};
|
std::array<PageState, NUM_ADDRESS_PAGES> cached_pages{};
|
||||||
|
Loading…
Reference in New Issue
Block a user