mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 12:05:23 +00:00
Implement vm::find_map; improve memory allocation
Add vm::user64k and vm::user1m constants Remove vm::user_space, unreserve it
This commit is contained in:
parent
9578e1e923
commit
aa4040bb7b
10 changed files with 139 additions and 67 deletions
|
@ -46,7 +46,7 @@ u32 local_addr = 0;
|
|||
/*
|
||||
* Get usable local memory size for a specific game SDK version
|
||||
* Example: For 0x00446000 (FW 4.46) we get a localSize of 0x0F900000 (249MB)
|
||||
*/
|
||||
*/
|
||||
u32 gcmGetLocalMemorySize(u32 sdk_version)
|
||||
{
|
||||
if (sdk_version >= 0x00220000)
|
||||
|
@ -397,16 +397,8 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
|
|||
m_config->current_config.coreFrequency = 500000000;
|
||||
|
||||
// Create contexts
|
||||
|
||||
u32 rsx_ctxaddr = 0;
|
||||
for (u32 addr = 0x30000000; addr < 0xC0000000; addr += 0x10000000)
|
||||
{
|
||||
if (vm::map(addr, 0x10000000, 0x400))
|
||||
{
|
||||
rsx_ctxaddr = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto ctx_area = vm::find_map(0x10000000, 0x10000000, 0x403);
|
||||
u32 rsx_ctxaddr = ctx_area ? ctx_area->addr : 0;
|
||||
|
||||
if (!rsx_ctxaddr || vm::falloc(rsx_ctxaddr, 0x400000) != rsx_ctxaddr)
|
||||
fmt::throw_exception("Failed to alloc rsx context.");
|
||||
|
@ -898,7 +890,7 @@ s32 cellGcmAddressToOffset(u32 address, vm::ptr<u32> offset)
|
|||
{
|
||||
result = address - 0xC0000000;
|
||||
}
|
||||
// Address in main memory else check
|
||||
// Address in main memory else check
|
||||
else
|
||||
{
|
||||
const u32 upper12Bits = offsetTable.ioAddress[address >> 20];
|
||||
|
|
|
@ -44,7 +44,7 @@ error_code sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
|
|||
}
|
||||
|
||||
// Allocate memory, write back the start address of the allocated area
|
||||
*alloc_addr = verify(HERE, vm::alloc(size, vm::user_space, align));
|
||||
*alloc_addr = verify(HERE, vm::alloc(size, align == 0x10000 ? vm::user64k : vm::user1m, align));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::
|
|||
const auto mem = idm::make_ptr<lv2_memory_alloca>(size, align, flags, ct.ptr);
|
||||
|
||||
// Allocate memory
|
||||
*alloc_addr = verify(HERE, vm::get(vm::user_space)->alloc(size, mem->align, &mem->shm));
|
||||
*alloc_addr = verify(HERE, vm::get(align == 0x10000 ? vm::user64k : vm::user1m)->alloc(size, mem->align, &mem->shm));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -103,7 +103,12 @@ error_code sys_memory_free(u32 addr)
|
|||
{
|
||||
sys_memory.warning("sys_memory_free(addr=0x%x)", addr);
|
||||
|
||||
const auto area = vm::get(vm::user_space);
|
||||
const auto area = vm::get(vm::any, addr);
|
||||
|
||||
if ((area->flags & 3) != 1)
|
||||
{
|
||||
return {CELL_EINVAL, addr};
|
||||
}
|
||||
|
||||
const auto shm = area->get(addr);
|
||||
|
||||
|
|
|
@ -45,13 +45,10 @@ error_code sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::
|
|||
case 0x40000000:
|
||||
case 0x80000000:
|
||||
{
|
||||
for (u64 addr = ::align<u64>(0x30000000, alignment); addr < 0xC0000000; addr += alignment)
|
||||
if (const auto area = vm::find_map(static_cast<u32>(size), static_cast<u32>(alignment), flags & SYS_MEMORY_PAGE_SIZE_MASK))
|
||||
{
|
||||
if (const auto area = vm::map(static_cast<u32>(addr), static_cast<u32>(size), flags))
|
||||
{
|
||||
*alloc_addr = static_cast<u32>(addr);
|
||||
return CELL_OK;
|
||||
}
|
||||
*alloc_addr = area->addr;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_ENOMEM;
|
||||
|
@ -191,6 +188,11 @@ error_code sys_mmapper_free_address(u32 addr)
|
|||
{
|
||||
sys_mmapper.error("sys_mmapper_free_address(addr=0x%x)", addr);
|
||||
|
||||
if (addr < 0x20000000 || addr >= 0xC0000000)
|
||||
{
|
||||
return {CELL_EINVAL, addr};
|
||||
}
|
||||
|
||||
// If page fault notify exists and an address in this area is faulted, we can't free the memory.
|
||||
auto pf_events = fxm::get_always<page_fault_event_entries>();
|
||||
semaphore_lock pf_lock(pf_events->pf_mutex);
|
||||
|
@ -209,7 +211,7 @@ error_code sys_mmapper_free_address(u32 addr)
|
|||
|
||||
if (!area)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
return {CELL_EINVAL, addr};
|
||||
}
|
||||
|
||||
if (!area.unique())
|
||||
|
@ -272,7 +274,7 @@ error_code sys_mmapper_map_shared_memory(u32 addr, u32 mem_id, u64 flags)
|
|||
|
||||
const auto area = vm::get(vm::any, addr);
|
||||
|
||||
if (!area || addr < 0x30000000 || addr >= 0xC0000000)
|
||||
if (!area || addr < 0x20000000 || addr >= 0xC0000000)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
@ -320,7 +322,7 @@ error_code sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm:
|
|||
|
||||
const auto area = vm::get(vm::any, start_addr);
|
||||
|
||||
if (!area || start_addr < 0x30000000 || start_addr >= 0xC0000000)
|
||||
if (!area || start_addr < 0x20000000 || start_addr >= 0xC0000000)
|
||||
{
|
||||
return {CELL_EINVAL, start_addr};
|
||||
}
|
||||
|
@ -353,7 +355,7 @@ error_code sys_mmapper_unmap_shared_memory(u32 addr, vm::ptr<u32> mem_id)
|
|||
|
||||
const auto area = vm::get(vm::any, addr);
|
||||
|
||||
if (!area || addr < 0x30000000 || addr >= 0xC0000000)
|
||||
if (!area || addr < 0x20000000 || addr >= 0xC0000000)
|
||||
{
|
||||
return {CELL_EINVAL, addr};
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ s32 sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size)
|
|||
}
|
||||
|
||||
const u32 end = (io >>= 20) + (size >>= 20);
|
||||
for (u32 ea = RSXIOMem.ea[io]; io < end;)
|
||||
for (u32 ea = RSXIOMem.ea[io]; io < end;)
|
||||
{
|
||||
RSXIOMem.io[ea++] = 0xFFFF;
|
||||
RSXIOMem.ea[io++] = 0xFFFF;
|
||||
|
@ -446,16 +446,11 @@ s32 sys_rsx_device_map(vm::ptr<u64> dev_addr, vm::ptr<u64> a2, u32 dev_id)
|
|||
return CELL_EINVAL; // sys_rsx_device_map called twice
|
||||
}
|
||||
|
||||
for (u32 addr = 0x30000000; addr < 0xC0000000; addr += 0x10000000)
|
||||
if (const auto area = vm::find_map(0x10000000, 0x10000000, 0x403))
|
||||
{
|
||||
if (vm::map(addr, 0x10000000, 0x400))
|
||||
{
|
||||
vm::falloc(addr, 0x400000);
|
||||
|
||||
m_sysrsx->rsx_context_addr = *dev_addr = addr;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
vm::falloc(area->addr, 0x400000);
|
||||
m_sysrsx->rsx_context_addr = *dev_addr = area->addr;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_ENOMEM;
|
||||
|
|
|
@ -20,19 +20,14 @@ error_code sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy
|
|||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
// Look for unmapped space (roughly)
|
||||
for (u32 found = 0x30000000; found <= 0xC0000000 - vsize; found += 0x1000000)
|
||||
// Look for unmapped space
|
||||
if (const auto area = vm::find_map(vsize, vsize == 0x10000000 ? 0x10000000 : 0x1000000, 2 | (flag & SYS_MEMORY_PAGE_SIZE_MASK)))
|
||||
{
|
||||
// Try to map
|
||||
if (const auto area = vm::map(found, vsize, flag))
|
||||
{
|
||||
// Alloc all memory (shall not fail)
|
||||
verify(HERE), area->alloc(vsize);
|
||||
// Alloc all memory (shall not fail)
|
||||
verify(HERE), area->alloc(vsize);
|
||||
|
||||
// Write a pointer for the allocated memory
|
||||
*addr = found;
|
||||
return CELL_OK;
|
||||
}
|
||||
// Write a pointer for the allocated memory
|
||||
*addr = area->addr;
|
||||
}
|
||||
|
||||
return CELL_ENOMEM;
|
||||
|
@ -52,7 +47,7 @@ error_code sys_vm_unmap(u32 addr)
|
|||
|
||||
if (!vm::unmap(addr))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
return {CELL_EINVAL, addr};
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
|
|
@ -711,6 +711,41 @@ namespace vm
|
|||
return imp_used(lock);
|
||||
}
|
||||
|
||||
static bool _test_map(u32 addr, u32 size)
|
||||
{
|
||||
for (auto& block : g_locations)
|
||||
{
|
||||
if (block && block->addr >= addr && block->addr <= addr + size - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (block && addr >= block->addr && addr <= block->addr + block->size - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::shared_ptr<block_t> _find_map(u32 size, u32 align, u64 flags)
|
||||
{
|
||||
for (u32 addr = ::align<u32>(0x20000000, align); addr < 0xC0000000; addr += align)
|
||||
{
|
||||
if (_test_map(addr, size))
|
||||
{
|
||||
auto block = std::make_shared<block_t>(addr, size, flags);
|
||||
|
||||
g_locations.emplace_back(block);
|
||||
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags)
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
@ -720,17 +755,9 @@ namespace vm
|
|||
fmt::throw_exception("Invalid arguments (addr=0x%x, size=0x%x)" HERE, addr, size);
|
||||
}
|
||||
|
||||
for (auto& block : g_locations)
|
||||
if (!_test_map(addr, size))
|
||||
{
|
||||
if (block->addr >= addr && block->addr <= addr + size - 1)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (addr >= block->addr && addr <= block->addr + block->size - 1)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
|
@ -748,6 +775,28 @@ namespace vm
|
|||
return block;
|
||||
}
|
||||
|
||||
std::shared_ptr<block_t> find_map(u32 orig_size, u32 align, u64 flags)
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
// Align to minimal page size
|
||||
const u32 size = ::align(orig_size, 0x10000);
|
||||
|
||||
// Check alignment
|
||||
if (align < 0x10000 || align != (0x80000000u >> ::cntlz32(align, true)))
|
||||
{
|
||||
fmt::throw_exception("Invalid alignment (size=0x%x, align=0x%x)" HERE, size, align);
|
||||
}
|
||||
|
||||
// Return if size is invalid
|
||||
if (!size || size > 0x40000000)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _find_map(size, align, flags);
|
||||
}
|
||||
|
||||
std::shared_ptr<block_t> unmap(u32 addr, bool must_be_empty)
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
@ -756,6 +805,16 @@ namespace vm
|
|||
{
|
||||
if (*it && (*it)->addr == addr)
|
||||
{
|
||||
if (must_be_empty && (*it)->flags & 0x3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!must_be_empty && ((*it)->flags & 0x3) != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (must_be_empty && (!it->unique() || (*it)->imp_used(lock)))
|
||||
{
|
||||
return *it;
|
||||
|
@ -779,7 +838,25 @@ namespace vm
|
|||
// return selected location
|
||||
if (location < g_locations.size())
|
||||
{
|
||||
return g_locations[location];
|
||||
auto& loc = g_locations[location];
|
||||
|
||||
if (!loc)
|
||||
{
|
||||
if (location == vm::user64k || location == vm::user1m)
|
||||
{
|
||||
g_mutex.lock_upgrade();
|
||||
|
||||
if (!loc)
|
||||
{
|
||||
// Deferred allocation
|
||||
loc = _find_map(0x10000000, 0x10000000, location == vm::user64k ? 0x201 : 0x401);
|
||||
}
|
||||
|
||||
g_mutex.lock_degrade();
|
||||
}
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -788,7 +865,7 @@ namespace vm
|
|||
// search location by address
|
||||
for (auto& block : g_locations)
|
||||
{
|
||||
if (addr >= block->addr && addr <= block->addr + block->size - 1)
|
||||
if (block && addr >= block->addr && addr <= block->addr + block->size - 1)
|
||||
{
|
||||
return block;
|
||||
}
|
||||
|
@ -804,9 +881,10 @@ namespace vm
|
|||
g_locations =
|
||||
{
|
||||
std::make_shared<block_t>(0x00010000, 0x1FFF0000), // main
|
||||
std::make_shared<block_t>(0x20000000, 0x10000000), // user
|
||||
std::make_shared<block_t>(0xC0000000, 0x10000000), // video
|
||||
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack
|
||||
nullptr, // user 64k pages
|
||||
nullptr, // user 1m pages
|
||||
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,9 +21,10 @@ namespace vm
|
|||
enum memory_location_t : uint
|
||||
{
|
||||
main,
|
||||
user_space,
|
||||
video,
|
||||
stack,
|
||||
user64k,
|
||||
user1m,
|
||||
|
||||
memory_location_max,
|
||||
any = 0xffffffff,
|
||||
|
@ -177,6 +178,9 @@ namespace vm
|
|||
// Create new memory block with specified parameters and return it
|
||||
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags = 0);
|
||||
|
||||
// Create new memory block with at arbitrary position with specified alignment
|
||||
std::shared_ptr<block_t> find_map(u32 size, u32 align, u64 flags = 0);
|
||||
|
||||
// Delete existing memory block with specified start address, return it
|
||||
std::shared_ptr<block_t> unmap(u32 addr, bool must_be_empty = false);
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ namespace rsx
|
|||
|
||||
// 'fake' initialize usermemory
|
||||
// todo: seriously, need to probly watch the replay memory map and just make sure its mapped before we copy rather than do this
|
||||
vm::falloc(0x20000000, 0x10000000, vm::user_space);
|
||||
const auto user_mem = vm::get(vm::user64k);
|
||||
vm::falloc(user_mem->addr, 0x10000000);
|
||||
|
||||
return contextInfo.context_id;
|
||||
}
|
||||
|
@ -37,7 +38,7 @@ namespace rsx
|
|||
{
|
||||
u32 fifo_size = 4;
|
||||
|
||||
// run through replay commands to figure out how big command buffer needs to be
|
||||
// run through replay commands to figure out how big command buffer needs to be
|
||||
// technically we could do this in batches if it gets too big, but we should be fine
|
||||
// as we aren't allocating anything on main memory, although it may make issues with iooffset later
|
||||
for (const auto& rc : frame->replay_commands)
|
||||
|
|
|
@ -1304,7 +1304,7 @@ void Emulator::Resume()
|
|||
|
||||
std::string dump;
|
||||
|
||||
for (u32 i = 0x10000; i < 0x30000000;)
|
||||
for (u32 i = 0x10000; i < 0x20000000;)
|
||||
{
|
||||
if (vm::check_addr(i))
|
||||
{
|
||||
|
|
|
@ -63,14 +63,14 @@ void kernel_explorer::Update()
|
|||
{
|
||||
m_tree->clear();
|
||||
|
||||
const auto vm_block = vm::get(vm::user_space);
|
||||
const auto dct = fxm::get_always<lv2_memory_container>();
|
||||
|
||||
if (!vm_block)
|
||||
if (!dct)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 total_memory_usage = vm_block->used();
|
||||
const u32 total_memory_usage = dct->used;
|
||||
|
||||
QTreeWidgetItem* root = new QTreeWidgetItem();
|
||||
root->setText(0, qstr(fmt::format("Process, ID = 0x00000001, Total Memory Usage = 0x%x (%0.2f MB)", total_memory_usage, (float)total_memory_usage / (1024 * 1024))));
|
||||
|
|
Loading…
Add table
Reference in a new issue