VSH: sys_mmapper

* Implement syscalls sys_mmapper_allocate_shared_memory_ext, sys_mmapper_allocate_shared_memory_from_container_ext.
* Implement multi-process shared memory allocations.
This commit is contained in:
Eladash 2020-01-02 18:07:52 +02:00 committed by Ani
parent 46df58b662
commit e4ba096190
6 changed files with 286 additions and 21 deletions

View File

@ -8,14 +8,14 @@ s32 sys_mmapper_allocate_memory(ppu_thread& ppu, u32 size, u64 flags, vm::ptr<u3
{ {
sysPrxForUser.notice("sys_mmapper_allocate_memory(size=0x%x, flags=0x%llx, mem_id=*0x%x)", size, flags, mem_id); sysPrxForUser.notice("sys_mmapper_allocate_memory(size=0x%x, flags=0x%llx, mem_id=*0x%x)", size, flags, mem_id);
return sys_mmapper_allocate_shared_memory(ppu, 0xffff000000000000ull, size, flags, mem_id); return sys_mmapper_allocate_shared_memory(ppu, SYS_MMAPPER_NO_SHM_KEY, size, flags, mem_id);
} }
s32 sys_mmapper_allocate_memory_from_container(ppu_thread& ppu, u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id) s32 sys_mmapper_allocate_memory_from_container(ppu_thread& ppu, u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id)
{ {
sysPrxForUser.notice("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id); sysPrxForUser.notice("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id);
return sys_mmapper_allocate_shared_memory_from_container(ppu, 0xffff000000000000ull, size, cid, flags, mem_id); return sys_mmapper_allocate_shared_memory_from_container(ppu, SYS_MMAPPER_NO_SHM_KEY, size, cid, flags, mem_id);
} }
s32 sys_mmapper_map_memory(ppu_thread& ppu, u32 addr, u32 mem_id, u64 flags) s32 sys_mmapper_map_memory(ppu_thread& ppu, u32 addr, u32 mem_id, u64 flags)

View File

@ -211,7 +211,7 @@ extern std::string ppu_get_syscall_name(u64 code)
case 325: return "sys_memory_container_destroy"; case 325: return "sys_memory_container_destroy";
case 326: return "sys_mmapper_allocate_fixed_address"; case 326: return "sys_mmapper_allocate_fixed_address";
case 327: return "sys_mmapper_enable_page_fault_notification"; case 327: return "sys_mmapper_enable_page_fault_notification";
case 328: return "sys_mmapper_allocate_shared_memory_ext"; case 328: return "sys_mmapper_allocate_shared_memory_from_container_ext";
case 329: return "sys_mmapper_free_shared_memory"; case 329: return "sys_mmapper_free_shared_memory";
case 330: return "sys_mmapper_allocate_address"; case 330: return "sys_mmapper_allocate_address";
case 331: return "sys_mmapper_free_address"; case 331: return "sys_mmapper_free_address";
@ -222,6 +222,7 @@ extern std::string ppu_get_syscall_name(u64 code)
case 336: return "sys_mmapper_change_address_access_right"; case 336: return "sys_mmapper_change_address_access_right";
case 337: return "sys_mmapper_search_and_map"; case 337: return "sys_mmapper_search_and_map";
case 338: return "sys_mmapper_get_shared_memory_attribute"; case 338: return "sys_mmapper_get_shared_memory_attribute";
case 339: return "sys_mmapper_allocate_shared_memory_ext";
case 341: return "sys_memory_container_create"; case 341: return "sys_memory_container_create";
case 342: return "sys_memory_container_destroy"; case 342: return "sys_memory_container_destroy";
case 343: return "sys_memory_container_get_size"; case 343: return "sys_memory_container_get_size";

View File

@ -332,7 +332,7 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
BIND_FUNC(sys_memory_container_destroy), //325 (0x145) DBG BIND_FUNC(sys_memory_container_destroy), //325 (0x145) DBG
BIND_FUNC(sys_mmapper_allocate_fixed_address), //326 (0x146) BIND_FUNC(sys_mmapper_allocate_fixed_address), //326 (0x146)
BIND_FUNC(sys_mmapper_enable_page_fault_notification), //327 (0x147) BIND_FUNC(sys_mmapper_enable_page_fault_notification), //327 (0x147)
null_func,//BIND_FUNC(sys_mmapper_allocate_shared_memory_ext) //328 (0x148) BIND_FUNC(sys_mmapper_allocate_shared_memory_from_container_ext), //328 (0x148)
BIND_FUNC(sys_mmapper_free_shared_memory), //329 (0x149) BIND_FUNC(sys_mmapper_free_shared_memory), //329 (0x149)
BIND_FUNC(sys_mmapper_allocate_address), //330 (0x14A) BIND_FUNC(sys_mmapper_allocate_address), //330 (0x14A)
BIND_FUNC(sys_mmapper_free_address), //331 (0x14B) BIND_FUNC(sys_mmapper_free_address), //331 (0x14B)
@ -343,7 +343,7 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
BIND_FUNC(sys_mmapper_change_address_access_right), //336 (0x150) BIND_FUNC(sys_mmapper_change_address_access_right), //336 (0x150)
BIND_FUNC(sys_mmapper_search_and_map), //337 (0x151) BIND_FUNC(sys_mmapper_search_and_map), //337 (0x151)
null_func,//BIND_FUNC(sys_mmapper_get_shared_memory_attribute) //338 (0x152) null_func,//BIND_FUNC(sys_mmapper_get_shared_memory_attribute) //338 (0x152)
null_func,//BIND_FUNC(sys_...) //339 (0x153) BIND_FUNC(sys_mmapper_allocate_shared_memory_ext), //339 (0x153)
null_func,//BIND_FUNC(sys_...) //340 (0x154) null_func,//BIND_FUNC(sys_...) //340 (0x154)
BIND_FUNC(sys_memory_container_create), //341 (0x155) BIND_FUNC(sys_memory_container_create), //341 (0x155)
BIND_FUNC(sys_memory_container_destroy), //342 (0x156) BIND_FUNC(sys_memory_container_destroy), //342 (0x156)

View File

@ -7,6 +7,8 @@
#include "Emu/Memory/vm_var.h" #include "Emu/Memory/vm_var.h"
#include "Utilities/VirtualMemory.h" #include "Utilities/VirtualMemory.h"
#include "sys_memory.h" #include "sys_memory.h"
#include "sys_sync.h"
#include "sys_process.h"
LOG_CHANNEL(sys_mmapper); LOG_CHANNEL(sys_mmapper);
@ -19,6 +21,26 @@ lv2_memory::lv2_memory(u32 size, u32 align, u64 flags, lv2_memory_container* ct)
{ {
} }
template<> DECLARE(ipc_manager<lv2_memory, u64>::g_ipc) {};
template <bool exclusive = false>
error_code create_lv2_shm(bool pshared, u64 ipc_key, u32 size, u32 align, u64 flags, lv2_memory_container* ct)
{
if (auto error = lv2_obj::create<lv2_memory>(pshared ? SYS_SYNC_PROCESS_SHARED : SYS_SYNC_NOT_PROCESS_SHARED, ipc_key, exclusive ? SYS_SYNC_NEWLY_CREATED : SYS_SYNC_NOT_CARE, [&]()
{
return std::make_shared<lv2_memory>(
size,
align,
flags,
ct);
}, false))
{
return error;
}
return CELL_OK;
}
error_code sys_mmapper_allocate_address(ppu_thread& ppu, u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr) error_code sys_mmapper_allocate_address(ppu_thread& ppu, u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
{ {
vm::temporary_unlock(ppu); vm::temporary_unlock(ppu);
@ -76,11 +98,16 @@ error_code sys_mmapper_allocate_fixed_address(ppu_thread& ppu)
return CELL_OK; return CELL_OK;
} }
error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size, u64 flags, vm::ptr<u32> mem_id) error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 ipc_key, u32 size, u64 flags, vm::ptr<u32> mem_id)
{ {
vm::temporary_unlock(ppu); vm::temporary_unlock(ppu);
sys_mmapper.warning("sys_mmapper_allocate_shared_memory(0x%llx, size=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, flags, mem_id); sys_mmapper.warning("sys_mmapper_allocate_shared_memory(ipc_key=0x%llx, size=0x%x, flags=0x%llx, mem_id=*0x%x)", ipc_key, size, flags, mem_id);
if (size == 0)
{
return CELL_EALIGN;
}
// Check page granularity // Check page granularity
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
@ -95,7 +122,6 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size
break; break;
} }
case SYS_MEMORY_PAGE_SIZE_64K: case SYS_MEMORY_PAGE_SIZE_64K:
{ {
if (size % 0x10000) if (size % 0x10000)
@ -105,7 +131,6 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size
break; break;
} }
default: default:
{ {
return CELL_EINVAL; return CELL_EINVAL;
@ -120,17 +145,25 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 unk, u32 size
return CELL_ENOMEM; return CELL_ENOMEM;
} }
// Generate a new mem ID if (auto error = create_lv2_shm(ipc_key != SYS_MMAPPER_NO_SHM_KEY, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, dct))
*mem_id = idm::make<lv2_obj, lv2_memory>(size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, dct); {
return error;
}
*mem_id = idm::last_id();
return CELL_OK; return CELL_OK;
} }
error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u64 unk, u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id) error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u64 ipc_key, u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id)
{ {
vm::temporary_unlock(ppu); vm::temporary_unlock(ppu);
sys_mmapper.warning("sys_mmapper_allocate_shared_memory_from_container(0x%llx, size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", unk, size, cid, flags, mem_id); sys_mmapper.warning("sys_mmapper_allocate_shared_memory_from_container(ipc_key=0x%llx, size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", ipc_key, size, cid, flags, mem_id);
if (size == 0)
{
return CELL_EALIGN;
}
// Check page granularity. // Check page granularity.
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK) switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
@ -145,7 +178,6 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6
break; break;
} }
case SYS_MEMORY_PAGE_SIZE_64K: case SYS_MEMORY_PAGE_SIZE_64K:
{ {
if (size % 0x10000) if (size % 0x10000)
@ -155,7 +187,6 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6
break; break;
} }
default: default:
{ {
return CELL_EINVAL; return CELL_EINVAL;
@ -183,9 +214,226 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6
return ct.ret; return ct.ret;
} }
// Generate a new mem ID if (auto error = create_lv2_shm(ipc_key != SYS_MMAPPER_NO_SHM_KEY, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, ct.ptr.get()))
*mem_id = idm::make<lv2_obj, lv2_memory>(size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, ct.ptr.get()); {
return error;
}
*mem_id = idm::last_id();
return CELL_OK;
}
error_code sys_mmapper_allocate_shared_memory_ext(ppu_thread& ppu, u64 ipc_key, u32 size, u32 flags, vm::ptr<mmapper_unk_entry_struct0> entries, s32 entry_count, vm::ptr<u32> mem_id)
{
vm::temporary_unlock(ppu);
sys_mmapper.todo("sys_mmapper_allocate_shared_memory_ext(ipc_key=0x%x, size=0x%x, flags=0x%x, entries=*0x%x, entry_count=0x%x, mem_id=*0x%x)", ipc_key, size, flags, entries, entry_count, mem_id);
if (size == 0)
{
return CELL_EALIGN;
}
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
{
case SYS_MEMORY_PAGE_SIZE_1M:
case 0:
{
if (size % 0x100000)
{
return CELL_EALIGN;
}
break;
}
case SYS_MEMORY_PAGE_SIZE_64K:
{
if (size % 0x10000)
{
return CELL_EALIGN;
}
break;
}
default:
{
return CELL_EINVAL;
}
}
if (flags & ~SYS_MEMORY_PAGE_SIZE_MASK)
{
return CELL_EINVAL;
}
if (entry_count <= 0 || entry_count > 0x10)
{
return CELL_EINVAL;
}
if constexpr (bool to_perm_check = false; true)
{
for (s32 i = 0; i < entry_count; i++)
{
const u64 type = entries[i].type;
// The whole structure contents are unknown
sys_mmapper.todo("sys_mmapper_allocate_shared_memory_ext(): entry type = 0x%llx", type);
switch (type)
{
case 0:
case 1:
case 3:
{
break;
}
case 5:
{
to_perm_check = true;
break;
}
default:
{
return CELL_EPERM;
}
}
}
if (to_perm_check)
{
if (flags != SYS_MEMORY_PAGE_SIZE_64K || !g_ps3_process_info.debug_or_root())
{
return CELL_EPERM;
}
}
}
// Get "default" memory container
const auto dct = g_fxo->get<lv2_memory_container>();
if (!dct->take(size))
{
return CELL_ENOMEM;
}
if (auto error = create_lv2_shm<true>(true, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, dct))
{
return error;
}
*mem_id = idm::last_id();
return CELL_OK;
}
error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread& ppu, u64 ipc_key, u32 size, u64 flags, u32 cid, vm::ptr<mmapper_unk_entry_struct0> entries, s32 entry_count, vm::ptr<u32> mem_id)
{
vm::temporary_unlock(ppu);
sys_mmapper.todo("sys_mmapper_allocate_shared_memory_from_container_ext(ipc_key=0x%x, size=0x%x, flags=0x%x, cid=0x%x, entries=*0x%x, entry_count=0x%x, mem_id=*0x%x)", ipc_key, size, flags, cid, entries,
entry_count, mem_id);
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
{
case SYS_MEMORY_PAGE_SIZE_1M:
case 0:
{
if (size % 0x100000)
{
return CELL_EALIGN;
}
break;
}
case SYS_MEMORY_PAGE_SIZE_64K:
{
if (size % 0x10000)
{
return CELL_EALIGN;
}
break;
}
default:
{
return CELL_EINVAL;
}
}
if (flags & ~SYS_MEMORY_PAGE_SIZE_MASK)
{
return CELL_EINVAL;
}
if (entry_count <= 0 || entry_count > 0x10)
{
return CELL_EINVAL;
}
if constexpr (bool to_perm_check = false; true)
{
for (s32 i = 0; i < entry_count; i++)
{
const u64 type = entries[i].type;
sys_mmapper.todo("sys_mmapper_allocate_shared_memory_from_container_ext(): entry type = 0x%llx", type);
switch (type)
{
case 0:
case 1:
case 3:
{
break;
}
case 5:
{
to_perm_check = true;
break;
}
default:
{
return CELL_EPERM;
}
}
}
if (to_perm_check)
{
if (flags != SYS_MEMORY_PAGE_SIZE_64K || !g_ps3_process_info.debug_or_root())
{
return CELL_EPERM;
}
}
}
const auto ct = idm::get<lv2_memory_container>(cid, [&](lv2_memory_container& ct) -> CellError
{
// Try to get "physical memory"
if (!ct.take(size))
{
return CELL_ENOMEM;
}
return {};
});
if (!ct)
{
return CELL_ESRCH;
}
if (ct.ret)
{
return ct.ret;
}
if (auto error = create_lv2_shm<true>(true, ipc_key, size, flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 : 0x100000, flags, ct.ptr.get()))
{
return error;
}
*mem_id = idm::last_id();
return CELL_OK; return CELL_OK;
} }

View File

@ -28,6 +28,11 @@ enum : u64
SYS_MEMORY_PAGE_FAULT_EVENT_KEY = 0xfffe000000000000ULL, SYS_MEMORY_PAGE_FAULT_EVENT_KEY = 0xfffe000000000000ULL,
}; };
enum : u64
{
SYS_MMAPPER_NO_SHM_KEY = 0xffff000000000000ull, // Unofficial name
};
enum : u64 enum : u64
{ {
SYS_MEMORY_PAGE_FAULT_CAUSE_NON_MAPPED = 0x2ULL, SYS_MEMORY_PAGE_FAULT_CAUSE_NON_MAPPED = 0x2ULL,
@ -59,6 +64,15 @@ struct page_fault_event_entries
cond_variable cond; cond_variable cond;
}; };
struct mmapper_unk_entry_struct0
{
be_t<u32> a; // 0x0
be_t<u32> b; // 0x4
be_t<u32> c; // 0x8
be_t<u32> d; // 0xc
be_t<u64> type; // 0x10
};
// Aux // Aux
class ppu_thread; class ppu_thread;
@ -67,8 +81,10 @@ error_code mmapper_thread_recover_page_fault(u32 id);
// SysCalls // SysCalls
error_code sys_mmapper_allocate_address(ppu_thread&, u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr); error_code sys_mmapper_allocate_address(ppu_thread&, u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr);
error_code sys_mmapper_allocate_fixed_address(ppu_thread&); error_code sys_mmapper_allocate_fixed_address(ppu_thread&);
error_code sys_mmapper_allocate_shared_memory(ppu_thread&, u64 unk, u32 size, u64 flags, vm::ptr<u32> mem_id); error_code sys_mmapper_allocate_shared_memory(ppu_thread&, u64 ipc_key, u32 size, u64 flags, vm::ptr<u32> mem_id);
error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread&, u64 unk, u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id); error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread&, u64 ipc_key, u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id);
error_code sys_mmapper_allocate_shared_memory_ext(ppu_thread&, u64 ipc_key, u32 size, u32 flags, vm::ptr<mmapper_unk_entry_struct0> src, s32 count, vm::ptr<u32> mem_id);
error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread&, u64 ipc_key, u32 size, u64 flags, u32 mc_id, vm::ptr<mmapper_unk_entry_struct0> entries, s32 entry_count, vm::ptr<u32> mem_id);
error_code sys_mmapper_change_address_access_right(ppu_thread&, u32 addr, u64 flags); error_code sys_mmapper_change_address_access_right(ppu_thread&, u32 addr, u64 flags);
error_code sys_mmapper_free_address(ppu_thread&, u32 addr); error_code sys_mmapper_free_address(ppu_thread&, u32 addr);
error_code sys_mmapper_free_shared_memory(ppu_thread&, u32 mem_id); error_code sys_mmapper_free_shared_memory(ppu_thread&, u32 mem_id);

View File

@ -171,13 +171,13 @@ public:
static void cleanup(); static void cleanup();
template <typename T, typename F> template <typename T, typename F>
static error_code create(u32 pshared, u64 ipc_key, s32 flags, F&& make) static error_code create(u32 pshared, u64 ipc_key, s32 flags, F&& make, bool key_not_zero = true)
{ {
switch (pshared) switch (pshared)
{ {
case SYS_SYNC_PROCESS_SHARED: case SYS_SYNC_PROCESS_SHARED:
{ {
if (ipc_key == 0) if (key_not_zero && ipc_key == 0)
{ {
return CELL_EINVAL; return CELL_EINVAL;
} }