mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-10-12 02:09:17 +00:00
vm/savestates: Rewrite and fix stack_guarded
This commit is contained in:
+47
-39
@@ -1185,6 +1185,39 @@ namespace vm
|
||||
|
||||
bool block_t::try_alloc(u32 addr, u64 bflags, u32 size, std::shared_ptr<utils::shm>&& shm) const
|
||||
{
|
||||
if (!size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->flags & stack_guarded)
|
||||
{
|
||||
ensure(this->size >= 0x100000);
|
||||
|
||||
if (addr < this->addr + 4096 || addr + size - 1 >= this->addr + this->size - 4096 - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Protect guard pages
|
||||
if (g_pages[addr / 4096 - 1] || g_pages[addr / 4096 + size / 4096])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Guard pages must be consecutive for non-edge allocations
|
||||
if (addr > this->addr + 4096 && g_pages[addr / 4096 - 2])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Same
|
||||
if (size + addr < this->addr + this->size - 4096 && g_pages[addr / 4096 + size / 4096 + 1])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if memory area is already mapped
|
||||
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
|
||||
{
|
||||
@@ -1194,9 +1227,6 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
const u32 page_addr = addr + (this->flags & stack_guarded ? 0x1000 : 0);
|
||||
const u32 page_size = size - (this->flags & stack_guarded ? 0x2000 : 0);
|
||||
|
||||
// No flags are default to readable/writable
|
||||
// Explicit (un...) flags are used to protect from such access
|
||||
u8 flags = 0;
|
||||
@@ -1225,15 +1255,8 @@ namespace vm
|
||||
flags |= page_1m_size;
|
||||
}
|
||||
|
||||
if (this->flags & stack_guarded)
|
||||
{
|
||||
// Mark overflow/underflow guard pages as allocated
|
||||
ensure(!g_pages[addr / 4096].exchange(page_allocated));
|
||||
ensure(!g_pages[addr / 4096 + size / 4096 - 1].exchange(page_allocated));
|
||||
}
|
||||
|
||||
// Map "real" memory pages; provide a function to search for mirrors with private member access
|
||||
_page_map(page_addr, flags, page_size, shm.get(), this->flags, [](vm::block_t* _this, utils::shm* shm)
|
||||
_page_map(addr, flags, size, shm.get(), this->flags, [](vm::block_t* _this, utils::shm* shm)
|
||||
{
|
||||
auto& map = (_this->m.*block_map)();
|
||||
|
||||
@@ -1262,17 +1285,7 @@ namespace vm
|
||||
{
|
||||
auto fill64 = [](u8* ptr, u64 data, usz count)
|
||||
{
|
||||
#if defined(_M_X64) && defined(_MSC_VER)
|
||||
__stosq(reinterpret_cast<u64*>(ptr), data, count);
|
||||
#elif defined(ARCH_X64)
|
||||
__asm__ ("mov %0, %%rdi; mov %1, %%rax; mov %2, %%rcx; rep stosq;"
|
||||
:
|
||||
: "r" (ptr), "r" (data), "r" (count)
|
||||
: "rdi", "rax", "rcx", "memory");
|
||||
#else
|
||||
for (usz i = 0; i < count; i++)
|
||||
reinterpret_cast<u64*>(ptr)[i] = data;
|
||||
#endif
|
||||
std::fill(ptr, ptr + count, data);
|
||||
};
|
||||
|
||||
const u32 enda = addr + size - 4096;
|
||||
@@ -1455,7 +1468,7 @@ namespace vm
|
||||
const u32 min_page_size = flags & block_size_4k ? 0x1000 : 0x10000;
|
||||
|
||||
// Align to minimal page size
|
||||
const u32 size = utils::align(orig_size, min_page_size) + (flags & stack_guarded ? 0x2000 : 0);
|
||||
const u32 size = utils::align(orig_size, min_page_size);
|
||||
|
||||
// Check alignment (it's page allocation, so passing small values there is just silly)
|
||||
if (align < min_page_size || align != (0x80000000u >> std::countl_zero(align)))
|
||||
@@ -1503,7 +1516,7 @@ namespace vm
|
||||
{
|
||||
if (try_alloc(addr, flags, size, std::move(shm)))
|
||||
{
|
||||
return addr + (flags & stack_guarded ? 0x1000 : 0);
|
||||
return addr;
|
||||
}
|
||||
|
||||
if (addr == max)
|
||||
@@ -1598,7 +1611,7 @@ namespace vm
|
||||
|
||||
vm::writer_lock lock;
|
||||
|
||||
const auto found = m_map.find(addr - (flags & stack_guarded ? 0x1000 : 0));
|
||||
const auto found = m_map.find(addr);
|
||||
|
||||
if (found == m_map.end())
|
||||
{
|
||||
@@ -1611,14 +1624,7 @@ namespace vm
|
||||
}
|
||||
|
||||
// Get allocation size
|
||||
const auto size = found->second.first - (flags & stack_guarded ? 0x2000 : 0);
|
||||
|
||||
if (flags & stack_guarded)
|
||||
{
|
||||
// Clear guard pages
|
||||
ensure(g_pages[addr / 4096 - 1].exchange(0) == page_allocated);
|
||||
ensure(g_pages[addr / 4096 + size / 4096].exchange(0) == page_allocated);
|
||||
}
|
||||
const auto size = found->second.first;
|
||||
|
||||
// Unmap "real" memory pages
|
||||
ensure(size == _page_unmap(addr, size, this->flags, found->second.second.get(), unmap_notification.event_data));
|
||||
@@ -1684,7 +1690,7 @@ namespace vm
|
||||
|
||||
for (auto& entry : (m.*block_map)())
|
||||
{
|
||||
result += entry.second.first - (flags & stack_guarded ? 0x2000 : 0);
|
||||
result += entry.second.first;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1834,7 +1840,7 @@ namespace vm
|
||||
for (const auto& [addr, shm] : m_map)
|
||||
{
|
||||
// Assume first page flags represent all the map
|
||||
ar(g_pages[addr / 4096 + !!(flags & stack_guarded)]);
|
||||
ar(g_pages[addr / 4096]);
|
||||
|
||||
ar(addr);
|
||||
ar(shm.first);
|
||||
@@ -1851,8 +1857,7 @@ namespace vm
|
||||
}
|
||||
|
||||
// Save raw binary image
|
||||
const u32 guard_size = flags & stack_guarded ? 0x1000 : 0;
|
||||
serialize_memory_bytes(ar, vm::get_super_ptr<u8>(addr + guard_size), shm.first - guard_size * 2);
|
||||
serialize_memory_bytes(ar, vm::get_super_ptr<u8>(addr), shm.first);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1918,6 +1923,10 @@ namespace vm
|
||||
{
|
||||
pflags |= block_size_1m;
|
||||
}
|
||||
else
|
||||
{
|
||||
pflags |= block_size_4k;
|
||||
}
|
||||
|
||||
// Map the memory through the same method as alloc() and falloc()
|
||||
// Copy the shared handle unconditionally
|
||||
@@ -1926,8 +1935,7 @@ namespace vm
|
||||
if (flags & preallocated)
|
||||
{
|
||||
// Load binary image
|
||||
const u32 guard_size = flags & stack_guarded ? 0x1000 : 0;
|
||||
serialize_memory_bytes(ar, vm::get_super_ptr<u8>(addr0 + guard_size), size0 - guard_size * 2);
|
||||
serialize_memory_bytes(ar, vm::get_super_ptr<u8>(addr0), size0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ static std::array<serial_ver_t, 34> s_serial_versions;
|
||||
return ::s_serial_versions[identifier].current_version;\
|
||||
}
|
||||
|
||||
SERIALIZATION_VER(global_version, 0, 24) // For stuff not listed here
|
||||
SERIALIZATION_VER(global_version, 0, 25) // For stuff not listed here
|
||||
SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/, 3/*PPU FNID and module*/)
|
||||
SERIALIZATION_VER(spu, 2, 1)
|
||||
SERIALIZATION_VER(lv2_sync, 3, 1)
|
||||
|
||||
Reference in New Issue
Block a user