mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-04 14:08:37 +00: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
4 changed files with 117 additions and 37 deletions
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue