mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
vm: allow 4k-aligned allocations for vm::stack
Fix utils::shm::map logic for MapViewOfFileEx
This commit is contained in:
parent
c49c7de427
commit
85fa0942e7
@ -167,17 +167,35 @@ namespace utils
|
||||
u8* shm::map(void* ptr, protection prot) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD access = 0;
|
||||
DWORD access = FILE_MAP_WRITE;
|
||||
switch (prot)
|
||||
{
|
||||
case protection::rw: access = FILE_MAP_WRITE; break;
|
||||
case protection::ro: access = FILE_MAP_READ; break;
|
||||
case protection::no: break;
|
||||
case protection::wx: access = FILE_MAP_WRITE | FILE_MAP_EXECUTE; break;
|
||||
case protection::rx: access = FILE_MAP_READ | FILE_MAP_EXECUTE; break;
|
||||
case protection::rw:
|
||||
case protection::ro:
|
||||
case protection::no:
|
||||
break;
|
||||
case protection::wx:
|
||||
case protection::rx:
|
||||
access |= FILE_MAP_EXECUTE;
|
||||
break;
|
||||
}
|
||||
|
||||
return static_cast<u8*>(::MapViewOfFileEx(m_handle, access, 0, 0, m_size, ptr));
|
||||
if (auto ret = static_cast<u8*>(::MapViewOfFileEx(m_handle, access, 0, 0, m_size, ptr)))
|
||||
{
|
||||
if (prot != protection::rw && prot != protection::wx)
|
||||
{
|
||||
DWORD old;
|
||||
if (!::VirtualProtect(ret, m_size, +prot, &old))
|
||||
{
|
||||
::UnmapViewOfFile(ret);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
#else
|
||||
return static_cast<u8*>(::mmap((void*)((u64)ptr & -0x10000), m_size, +prot, MAP_SHARED | (ptr ? MAP_FIXED : 0), m_file, 0));
|
||||
#endif
|
||||
|
@ -348,7 +348,7 @@ void ppu_thread::on_init(const std::shared_ptr<void>& _this)
|
||||
if (!stack_addr)
|
||||
{
|
||||
// Allocate stack + gap between stacks
|
||||
auto new_stack_base = vm::alloc(stack_size + 4096, vm::stack);
|
||||
auto new_stack_base = vm::alloc(stack_size + 4096, vm::stack, 4096);
|
||||
if (!new_stack_base)
|
||||
{
|
||||
fmt::throw_exception("Out of stack memory (size=0x%x)" HERE, stack_size);
|
||||
|
@ -276,10 +276,8 @@ namespace vm
|
||||
// Memory pages
|
||||
std::array<memory_page, 0x100000000 / 4096> g_pages{};
|
||||
|
||||
static void _page_map(u32 addr, u8 flags, utils::shm& shm)
|
||||
static void _page_map(u32 addr, u8 flags, u32 size, utils::shm* shm)
|
||||
{
|
||||
const u32 size = shm.size();
|
||||
|
||||
if (!size || (size | addr) % 4096 || flags & page_allocated)
|
||||
{
|
||||
fmt::throw_exception("Invalid arguments (addr=0x%x, size=0x%x)" HERE, addr, size);
|
||||
@ -293,7 +291,12 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
if (shm.map_critical(g_base_addr + addr) != g_base_addr + addr)
|
||||
if (!shm)
|
||||
{
|
||||
utils::memory_protect(g_base_addr + addr, size, utils::protection::rw);
|
||||
std::memset(g_base_addr + addr, 0, size);
|
||||
}
|
||||
else if (shm->map_critical(g_base_addr + addr) != g_base_addr + addr)
|
||||
{
|
||||
fmt::throw_exception("Memory mapping failed - blame Windows (addr=0x%x, size=0x%x, flags=0x%x)", addr, size, flags);
|
||||
}
|
||||
@ -375,28 +378,30 @@ namespace vm
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _page_unmap(u32 addr, utils::shm& shm)
|
||||
static u32 _page_unmap(u32 addr, u32 max_size, utils::shm* shm)
|
||||
{
|
||||
const u32 size = shm.size();
|
||||
|
||||
if (!size || (size | addr) % 4096)
|
||||
if (!max_size || (max_size | addr) % 4096)
|
||||
{
|
||||
fmt::throw_exception("Invalid arguments (addr=0x%x, size=0x%x)" HERE, addr, size);
|
||||
fmt::throw_exception("Invalid arguments (addr=0x%x, max_size=0x%x)" HERE, addr, max_size);
|
||||
}
|
||||
|
||||
// Determine deallocation size
|
||||
u32 size = 0;
|
||||
bool is_exec = false;
|
||||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + max_size / 4096; i++)
|
||||
{
|
||||
if ((g_pages[i].flags & page_allocated) == 0)
|
||||
{
|
||||
fmt::throw_exception("Memory not mapped (addr=0x%x, size=0x%x, current_addr=0x%x)" HERE, addr, size, i * 4096);
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_pages[i].flags & page_executable)
|
||||
{
|
||||
is_exec = true;
|
||||
}
|
||||
|
||||
size += 4096;
|
||||
}
|
||||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
@ -407,7 +412,14 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
shm.unmap_critical(g_base_addr + addr);
|
||||
if (!shm)
|
||||
{
|
||||
utils::memory_protect(g_base_addr + addr, size, utils::protection::no);
|
||||
}
|
||||
else
|
||||
{
|
||||
shm->unmap_critical(g_base_addr + addr);
|
||||
}
|
||||
|
||||
if (is_exec)
|
||||
{
|
||||
@ -418,6 +430,8 @@ namespace vm
|
||||
{
|
||||
utils::memory_decommit(g_stat_addr + addr, size);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool check_addr(u32 addr, u32 size, u8 flags)
|
||||
@ -486,10 +500,8 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
bool block_t::try_alloc(u32 addr, u8 flags, std::shared_ptr<utils::shm>&& shm)
|
||||
bool block_t::try_alloc(u32 addr, u8 flags, u32 size, std::shared_ptr<utils::shm>&& shm)
|
||||
{
|
||||
const u32 size = shm->size();
|
||||
|
||||
// Check if memory area is already mapped
|
||||
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
|
||||
{
|
||||
@ -500,7 +512,7 @@ namespace vm
|
||||
}
|
||||
|
||||
// Map "real" memory pages
|
||||
_page_map(addr, flags, *shm);
|
||||
_page_map(addr, flags, size, shm.get());
|
||||
|
||||
// Add entry
|
||||
m_map[addr] = std::move(shm);
|
||||
@ -539,6 +551,13 @@ namespace vm
|
||||
utils::memory_commit(g_reservations + 0xfff0000, 0x10000);
|
||||
utils::memory_commit(g_reservations2 + 0xfff0000, 0x10000);
|
||||
}
|
||||
|
||||
if (flags & 0x100)
|
||||
{
|
||||
// Special path for 4k-aligned pages
|
||||
m_common = std::make_shared<utils::shm>(size);
|
||||
verify(HERE), m_common->map_critical(vm::base(addr), utils::protection::no) == vm::base(addr);
|
||||
}
|
||||
}
|
||||
|
||||
block_t::~block_t()
|
||||
@ -547,9 +566,18 @@ namespace vm
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
// Deallocate all memory
|
||||
for (auto& entry : m_map)
|
||||
for (auto it = m_map.begin(), end = m_map.end(); it != end;)
|
||||
{
|
||||
_page_unmap(entry.first, *entry.second);
|
||||
const auto next = std::next(it);
|
||||
const auto size = (next == end ? this->addr + this->size : next->first) - it->first;
|
||||
_page_unmap(it->first, size, it->second.get());
|
||||
it = next;
|
||||
}
|
||||
|
||||
// Special path for 4k-aligned pages
|
||||
if (m_common)
|
||||
{
|
||||
m_common->unmap_critical(vm::base(addr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,11 +592,14 @@ namespace vm
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
// Determine minimal alignment
|
||||
const u32 min_page_size = flags & 0x100 ? 0x1000 : 0x10000;
|
||||
|
||||
// Align to minimal page size
|
||||
const u32 size = ::align(orig_size, 0x10000);
|
||||
const u32 size = ::align(orig_size, min_page_size);
|
||||
|
||||
// Check alignment (it's page allocation, so passing small values there is just silly)
|
||||
if (align < 0x10000 || align != (0x80000000u >> cntlz32(align, true)))
|
||||
if (align < min_page_size || align != (0x80000000u >> cntlz32(align, true)))
|
||||
{
|
||||
fmt::throw_exception("Invalid alignment (size=0x%x, align=0x%x)" HERE, size, align);
|
||||
}
|
||||
@ -591,12 +622,19 @@ namespace vm
|
||||
}
|
||||
|
||||
// Create or import shared memory object
|
||||
std::shared_ptr<utils::shm> shm = src ? std::shared_ptr<utils::shm>(*src) : std::make_shared<utils::shm>(size);
|
||||
std::shared_ptr<utils::shm> shm;
|
||||
|
||||
if (m_common)
|
||||
verify(HERE), !src;
|
||||
else if (src)
|
||||
shm = *src;
|
||||
else
|
||||
shm = std::make_shared<utils::shm>(size);
|
||||
|
||||
// Search for an appropriate place (unoptimized)
|
||||
for (u32 addr = ::align(this->addr, align); addr < this->addr + this->size - 1; addr += align)
|
||||
{
|
||||
if (try_alloc(addr, pflags, std::move(shm)))
|
||||
if (try_alloc(addr, pflags, size, std::move(shm)))
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
@ -609,8 +647,11 @@ namespace vm
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
// align to minimal page size
|
||||
const u32 size = ::align(orig_size, 0x10000);
|
||||
// Determine minimal alignment
|
||||
const u32 min_page_size = flags & 0x100 ? 0x1000 : 0x10000;
|
||||
|
||||
// Align to minimal page size
|
||||
const u32 size = ::align(orig_size, min_page_size);
|
||||
|
||||
// return if addr or size is invalid
|
||||
if (!size || size > this->size || addr < this->addr || addr + size - 1 > this->addr + this->size - 1)
|
||||
@ -629,7 +670,17 @@ namespace vm
|
||||
pflags |= page_64k_size;
|
||||
}
|
||||
|
||||
if (!try_alloc(addr, pflags, src ? std::shared_ptr<utils::shm>(*src) : std::make_shared<utils::shm>(size)))
|
||||
// Create or import shared memory object
|
||||
std::shared_ptr<utils::shm> shm;
|
||||
|
||||
if (m_common)
|
||||
verify(HERE), !src;
|
||||
else if (src)
|
||||
shm = *src;
|
||||
else
|
||||
shm = std::make_shared<utils::shm>(size);
|
||||
|
||||
if (!try_alloc(addr, pflags, size, std::move(shm)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -655,10 +706,12 @@ namespace vm
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = found->second->size();
|
||||
// Approximate allocation size
|
||||
const auto next = std::next(found);
|
||||
const auto size = (next == m_map.end() ? this->addr + this->size : next->first) - found->first;
|
||||
|
||||
// Unmap "real" memory pages
|
||||
_page_unmap(addr, *found->second);
|
||||
result = _page_unmap(addr, size, found->second.get());
|
||||
|
||||
// Remove entry
|
||||
m_map.erase(found);
|
||||
@ -697,6 +750,12 @@ namespace vm
|
||||
return {addr, nullptr};
|
||||
}
|
||||
|
||||
// Special path
|
||||
if (m_common)
|
||||
{
|
||||
return {this->addr, m_common};
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (std::max<u32>(size, addr - found->first + size) > found->second->size())
|
||||
{
|
||||
@ -896,7 +955,7 @@ namespace vm
|
||||
std::make_shared<block_t>(0x20000000, 0x10000000, 0x201), // user 64k pages
|
||||
nullptr, // user 1m pages
|
||||
std::make_shared<block_t>(0xC0000000, 0x10000000), // video
|
||||
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack
|
||||
std::make_shared<block_t>(0xD0000000, 0x10000000, 0x101), // stack
|
||||
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved
|
||||
};
|
||||
}
|
||||
|
@ -146,7 +146,10 @@ namespace vm
|
||||
// Mapped regions: addr -> shm handle
|
||||
std::map<u32, std::shared_ptr<utils::shm>> m_map;
|
||||
|
||||
bool try_alloc(u32 addr, u8 flags, std::shared_ptr<utils::shm>&&);
|
||||
// Common mapped region for special cases
|
||||
std::shared_ptr<utils::shm> m_common;
|
||||
|
||||
bool try_alloc(u32 addr, u8 flags, u32 size, std::shared_ptr<utils::shm>&&);
|
||||
|
||||
public:
|
||||
block_t(u32 addr, u32 size, u64 flags = 0);
|
||||
|
Loading…
Reference in New Issue
Block a user