sys_memory, sys_mmapper rewritten

LogBase::Fatal() removed
This commit is contained in:
Nekotekina 2015-07-10 17:45:16 +03:00
parent 39629c5c7a
commit 2d37c6b5e2
20 changed files with 598 additions and 456 deletions

View file

@ -9,16 +9,16 @@
thread_local spu_mfc_arg_t raw_spu_mfc[8] = {}; thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
RawSPUThread::RawSPUThread(const std::string& name, u32 index) RawSPUThread::RawSPUThread(const std::string& name, u32 index)
: SPUThread(CPU_THREAD_RAW_SPU, name, WRAP_EXPR(fmt::format("RawSPU[0x%x] Thread (%s)[0x%08x]", GetId(), GetName(), PC)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) : SPUThread(CPU_THREAD_RAW_SPU, name, COPY_EXPR(fmt::format("RawSPU_%d[0x%x] Thread (%s)[0x%08x]", index, GetId(), GetName(), PC)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index)
{ {
Memory.Map(offset, 0x40000); vm::page_map(offset, 0x40000, vm::page_readable | vm::page_writable);
} }
RawSPUThread::~RawSPUThread() RawSPUThread::~RawSPUThread()
{ {
join(); join();
Memory.Unmap(offset); vm::page_unmap(offset, 0x40000);
} }
void RawSPUThread::start() void RawSPUThread::start()

View file

@ -66,10 +66,26 @@ void MemoryBase::Close()
bool MemoryBase::Map(const u32 addr, const u32 size) bool MemoryBase::Map(const u32 addr, const u32 size)
{ {
assert(size && (size | addr) % 4096 == 0); if (!size || (size | addr) % 4096)
{
throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x)", addr, size);
}
std::lock_guard<std::mutex> lock(Memory.mutex); std::lock_guard<std::mutex> lock(Memory.mutex);
for (auto& block : MemoryBlocks)
{
if (block->GetStartAddr() >= addr && block->GetStartAddr() <= addr + size - 1)
{
return false;
}
if (addr >= block->GetStartAddr() && addr <= block->GetEndAddr())
{
return false;
}
}
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++) for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
{ {
if (vm::check_addr(i * 4096, 4096)) if (vm::check_addr(i * 4096, 4096))
@ -78,9 +94,8 @@ bool MemoryBase::Map(const u32 addr, const u32 size)
} }
} }
MemoryBlocks.push_back((new MemoryBlock())->SetRange(addr, size)); MemoryBlocks.push_back((new DynamicMemoryBlock())->SetRange(addr, size));
LOG_WARNING(MEMORY, "Memory mapped at 0x%x: size=0x%x", addr, size);
return true; return true;
} }
@ -97,9 +112,25 @@ bool MemoryBase::Unmap(const u32 addr)
return true; return true;
} }
} }
return false; return false;
} }
MemoryBlock* MemoryBase::Get(const u32 addr)
{
std::lock_guard<std::mutex> lock(Memory.mutex);
for (auto& block : MemoryBlocks)
{
if (block->GetStartAddr() == addr)
{
return block;
}
}
return nullptr;
}
MemBlockInfo::MemBlockInfo(u32 addr, u32 size) MemBlockInfo::MemBlockInfo(u32 addr, u32 size)
: MemInfo(addr, size) : MemInfo(addr, size)
{ {

View file

@ -28,7 +28,8 @@ public:
{ {
DynamicMemoryBlock RAM; DynamicMemoryBlock RAM;
DynamicMemoryBlock Userspace; DynamicMemoryBlock Userspace;
} PSV; }
PSV;
struct struct
{ {
@ -37,7 +38,8 @@ public:
DynamicMemoryBlock RAM; DynamicMemoryBlock RAM;
DynamicMemoryBlock Kernel; DynamicMemoryBlock Kernel;
DynamicMemoryBlock Userspace; DynamicMemoryBlock Userspace;
} PSP; }
PSP;
bool m_inited; bool m_inited;
@ -51,10 +53,6 @@ public:
Close(); Close();
} }
void RegisterPages(u32 addr, u32 size);
void UnregisterPages(u32 addr, u32 size);
void Init(MemoryType type); void Init(MemoryType type);
void Close(); void Close();
@ -82,6 +80,8 @@ public:
bool Map(const u32 addr, const u32 size); bool Map(const u32 addr, const u32 size);
bool Unmap(const u32 addr); bool Unmap(const u32 addr);
MemoryBlock* Get(const u32 addr);
}; };
extern MemoryBase Memory; extern MemoryBase Memory;

View file

@ -16,8 +16,7 @@ void LogBase::LogOutput(LogType type, const std::string& text) const
case LogNotice: LOG_NOTICE(HLE, GetName() + ": " + text); break; case LogNotice: LOG_NOTICE(HLE, GetName() + ": " + text); break;
case LogSuccess: LOG_SUCCESS(HLE, GetName() + ": " + text); break; case LogSuccess: LOG_SUCCESS(HLE, GetName() + ": " + text); break;
case LogWarning: LOG_WARNING(HLE, GetName() + ": " + text); break; case LogWarning: LOG_WARNING(HLE, GetName() + ": " + text); break;
case LogError: LOG_ERROR(HLE, GetName() + " error: " + text); break; case LogError: LOG_ERROR(HLE, GetName() + ": " + text); break;
case LogTodo: LOG_ERROR(HLE, GetName() + " TODO: " + text); break; case LogTodo: LOG_ERROR(HLE, GetName() + " TODO: " + text); break;
case LogFatal: throw EXCEPTION("%s error: %s", GetName().c_str(), text.c_str());
} }
} }

View file

@ -11,7 +11,6 @@ class LogBase
LogSuccess, LogSuccess,
LogWarning, LogWarning,
LogError, LogError,
LogFatal,
LogTodo, LogTodo,
}; };
@ -63,11 +62,6 @@ public:
LogPrepare(LogError, fmt, fmt::do_unveil(args)...); LogPrepare(LogError, fmt, fmt::do_unveil(args)...);
} }
template<typename... Args> force_inline void Fatal(const char* fmt, Args... args) const
{
LogPrepare(LogFatal, fmt, fmt::do_unveil(args)...);
}
template<typename... Args> force_inline void Todo(const char* fmt, Args... args) const template<typename... Args> force_inline void Todo(const char* fmt, Args... args) const
{ {
LogPrepare(LogTodo, fmt, fmt::do_unveil(args)...); LogPrepare(LogTodo, fmt, fmt::do_unveil(args)...);

View file

@ -777,7 +777,7 @@ s32 cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
} }
else else
{ {
cellAdec.Fatal("cellAdecGetPcm(): unsupported frame format (channels=%d, format=%d)", frame->channels, frame->format); throw EXCEPTION("Unsupported frame format (channels=%d, format=%d)", frame->channels, frame->format);
} }
} }

View file

@ -645,7 +645,7 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInf
if (mode != CELL_VDEC_DEC_MODE_NORMAL) if (mode != CELL_VDEC_DEC_MODE_NORMAL)
{ {
cellVdec.Fatal("cellVdecDecodeAu(): unsupported decoding mode (%d)", mode); throw EXCEPTION("Unsupported decoding mode (%d)", mode);
} }
// TODO: check info // TODO: check info
@ -711,13 +711,13 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
default: default:
{ {
cellVdec.Fatal("cellVdecGetPicture: unknown formatType(%d)", type); throw EXCEPTION("Unknown formatType(%d)", type);
} }
} }
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709) if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
{ {
cellVdec.Fatal("cellVdecGetPicture: unknown colorMatrixType(%d)", format->colorMatrixType); throw EXCEPTION("Unknown colorMatrixType(%d)", format->colorMatrixType);
} }
if (alpha_plane) if (alpha_plane)
@ -733,7 +733,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
default: default:
{ {
cellVdec.Fatal("cellVdecGetPicture: unknown pix_fmt(%d)", f); throw EXCEPTION("Unknown pix_fmt(%d)", f);
} }
} }
@ -775,7 +775,7 @@ s32 _nid_a21aa896(PPUThread& CPU, u32 handle, vm::cptr<CellVdecPicFormat2> forma
if (arg4 || format2->unk0 || format2->unk1) if (arg4 || format2->unk0 || format2->unk1)
{ {
cellVdec.Fatal("_nid_a21aa896(): unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format2->unk0, format2->unk1); throw EXCEPTION("Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format2->unk0, format2->unk1);
} }
vm::stackvar<CellVdecPicFormat> format(CPU); vm::stackvar<CellVdecPicFormat> format(CPU);
@ -924,7 +924,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
{ {
auto mp2 = vm::ptr<CellVdecMpeg2Info>::make(info.addr() + sizeof32(CellVdecPicItem)); auto mp2 = vm::ptr<CellVdecMpeg2Info>::make(info.addr() + sizeof32(CellVdecPicItem));
cellVdec.Fatal("cellVdecGetPicItem(MPEG2)"); throw EXCEPTION("MPEG2");
} }
*picItem = info; *picItem = info;

View file

@ -230,7 +230,7 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout
if (old != lwmutex_reserved) if (old != lwmutex_reserved)
{ {
sysPrxForUser.Fatal("sys_lwmutex_lock(lwmutex=*0x%x): locking failed (owner=0x%x)", lwmutex, old); throw EXCEPTION("Locking failed (lwmutex=*0x%x, owner=0x%x)", lwmutex, old);
} }
return CELL_OK; return CELL_OK;
@ -301,7 +301,7 @@ s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
if (old != lwmutex_reserved) if (old != lwmutex_reserved)
{ {
sysPrxForUser.Fatal("sys_lwmutex_trylock(lwmutex=*0x%x): locking failed (owner=0x%x)", lwmutex, old); throw EXCEPTION("Locking failed (lwmutex=*0x%x, owner=0x%x)", lwmutex, old);
} }
} }
@ -590,7 +590,7 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
if (old != lwmutex_reserved) if (old != lwmutex_reserved)
{ {
sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): locking failed (lwmutex->owner=0x%x)", lwcond, old); throw EXCEPTION("Locking failed (lwmutex=*0x%x, owner=0x%x)", lwmutex, old);
} }
return res; return res;
@ -619,14 +619,13 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
if (old != lwmutex_reserved) if (old != lwmutex_reserved)
{ {
sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): locking failed after timeout (lwmutex->owner=0x%x)", lwcond, old); throw EXCEPTION("Locking failed (lwmutex=*0x%x, owner=0x%x)", lwmutex, old);
} }
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): unexpected syscall result (0x%x)", lwcond, res); throw EXCEPTION("Unexpected syscall result (lwcond=*0x%x, result=0x%x)", lwcond, res);
return res;
} }
s64 sys_time_get_system_time() s64 sys_time_get_system_time()
@ -1168,9 +1167,7 @@ s32 _sys_printf(vm::cptr<char> fmt, ppu_va_args_t va_args)
sysPrxForUser.Todo("_sys_printf(fmt=*0x%x, ...)", fmt); sysPrxForUser.Todo("_sys_printf(fmt=*0x%x, ...)", fmt);
// probably, assertion failed // probably, assertion failed
sysPrxForUser.Fatal("_sys_printf: \n%s", fmt.get_ptr()); throw EXCEPTION("%s", fmt.get_ptr());
Emu.Pause();
return CELL_OK;
} }
s32 sys_process_get_paramsfo(vm::ptr<char> buffer) s32 sys_process_get_paramsfo(vm::ptr<char> buffer)

View file

@ -97,7 +97,7 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
if (!open_mode) if (!open_mode)
{ {
sys_fs.Fatal("sys_fs_open('%s'): invalid or unimplemented flags (%#o)", path.get_ptr(), flags); throw EXCEPTION("Invalid or unimplemented flags (%#o): '%s'", flags, path.get_ptr());
} }
std::shared_ptr<vfsStream> file(Emu.GetVFS().OpenFile(path.get_ptr(), open_mode)); std::shared_ptr<vfsStream> file(Emu.GetVFS().OpenFile(path.get_ptr(), open_mode));

View file

@ -133,7 +133,7 @@ s32 _sys_lwmutex_unlock(u32 lwmutex_id)
if (mutex->signaled) if (mutex->signaled)
{ {
sys_lwmutex.Fatal("_sys_lwmutex_unlock(lwmutex_id=0x%x): already signaled", lwmutex_id); throw EXCEPTION("Already signaled (lwmutex_id=0x%x)", lwmutex_id);
} }
mutex->signaled++; mutex->signaled++;

View file

@ -5,95 +5,196 @@
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "sys_memory.h" #include "sys_memory.h"
#include <map>
SysCallBase sys_memory("sys_memory"); SysCallBase sys_memory("sys_memory");
s32 sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr) lv2_memory_container_t::lv2_memory_container_t(u32 size)
: size(size)
, id(Emu.GetIdManager().get_current_id())
{ {
sys_memory.Log("sys_memory_allocate(size=0x%x, flags=0x%x)", size, flags); }
// Check page size. s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
u32 addr; {
sys_memory.Warning("sys_memory_allocate(size=0x%x, flags=0x%llx, alloc_addr=*0x%x)", size, flags, alloc_addr);
LV2_LOCK;
// Check allocation size
switch(flags) switch(flags)
{ {
case SYS_MEMORY_PAGE_SIZE_1M: case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) return CELL_EALIGN; {
addr = (u32)Memory.Alloc(size, 0x100000); if (size % 0x100000)
break; {
return CELL_EALIGN;
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff) return CELL_EALIGN;
addr = (u32)Memory.Alloc(size, 0x10000);
break;
default: return CELL_EINVAL;
} }
if (!addr) break;
return CELL_ENOMEM; }
// Write back the start address of the allocated area. case SYS_MEMORY_PAGE_SIZE_64K:
sys_memory.Log("Memory allocated! [addr: 0x%x, size: 0x%x]", addr, size); {
vm::write32(alloc_addr_addr, addr); if (size % 0x10000)
{
return CELL_EALIGN;
}
break;
}
default:
{
return CELL_EINVAL;
}
}
// Available memory reserved for containers
u32 available = 0;
// Check all containers
for (auto& ct : Emu.GetIdManager().get_all<lv2_memory_container_t>())
{
available += ct->size - ct->taken;
}
// Check available memory
if (Memory.GetUserMemAvailSize() < available + size)
{
return CELL_ENOMEM;
}
// Allocate memory
const u32 addr =
flags == SYS_MEMORY_PAGE_SIZE_1M ? Memory.Alloc(size, 0x100000) :
flags == SYS_MEMORY_PAGE_SIZE_64K ? Memory.Alloc(size, 0x10000) :
throw EXCEPTION("Unexpected flags");
if (!addr)
{
return CELL_ENOMEM;
}
// Write back the start address of the allocated area
*alloc_addr = addr;
return CELL_OK; return CELL_OK;
} }
s32 sys_memory_allocate_from_container(u32 size, u32 cid, u32 flags, u32 alloc_addr_addr) s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr)
{ {
sys_memory.Log("sys_memory_allocate_from_container(size=0x%x, cid=0x%x, flags=0x%x)", size, cid, flags); sys_memory.Warning("sys_memory_allocate_from_container(size=0x%x, cid=0x%x, flags=0x%llx, alloc_addr=*0x%x)", size, cid, flags, alloc_addr);
// Check if this container ID is valid. LV2_LOCK;
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid);
// Check if this container ID is valid
const auto ct = Emu.GetIdManager().get<lv2_memory_container_t>(cid);
if (!ct) if (!ct)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// Check page size. // Check allocation size
switch(flags) switch (flags)
{ {
case SYS_MEMORY_PAGE_SIZE_1M: case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) return CELL_EALIGN; {
ct->addr = (u32)Memory.Alloc(size, 0x100000); if (size % 0x100000)
break; {
return CELL_EALIGN;
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff) return CELL_EALIGN;
ct->addr = (u32)Memory.Alloc(size, 0x10000);
break;
default: return CELL_EINVAL;
} }
// Store the address and size in the container. break;
if(!ct->addr) }
case SYS_MEMORY_PAGE_SIZE_64K:
{
if (size % 0x10000)
{
return CELL_EALIGN;
}
break;
}
default:
{
return CELL_EINVAL;
}
}
if (ct->taken > ct->size)
{
throw EXCEPTION("Unexpected amount of memory taken (0x%x, size=0x%x)", ct->taken.load(), ct->size);
}
// Check memory availability
if (size > ct->size - ct->taken)
{
return CELL_ENOMEM; return CELL_ENOMEM;
ct->size = size; }
// Allocate memory
const u32 addr =
flags == SYS_MEMORY_PAGE_SIZE_1M ? Memory.Alloc(size, 0x100000) :
flags == SYS_MEMORY_PAGE_SIZE_64K ? Memory.Alloc(size, 0x10000) :
throw EXCEPTION("Unexpected flags");
if (!addr)
{
throw EXCEPTION("Memory not allocated (ct=0x%x, size=0x%x)", cid, size);
}
// Store the address and size in the container
ct->allocs.emplace(addr, size);
ct->taken += size;
// Write back the start address of the allocated area. // Write back the start address of the allocated area.
sys_memory.Log("Memory allocated! [addr: 0x%x, size: 0x%x]", ct->addr, ct->size); *alloc_addr = addr;
vm::write32(alloc_addr_addr, ct->addr);
return CELL_OK; return CELL_OK;
} }
s32 sys_memory_free(u32 start_addr) s32 sys_memory_free(u32 addr)
{ {
sys_memory.Log("sys_memory_free(start_addr=0x%x)", start_addr); sys_memory.Warning("sys_memory_free(addr=0x%x)", addr);
// Release the allocated memory. LV2_LOCK;
if(!Memory.Free(start_addr))
// Check all memory containers
for (auto& ct : Emu.GetIdManager().get_all<lv2_memory_container_t>())
{
auto found = ct->allocs.find(addr);
if (found != ct->allocs.end())
{
if (!Memory.Free(addr))
{
throw EXCEPTION("Memory not deallocated (cid=0x%x, addr=0x%x, size=0x%x)", ct->id, addr, found->second);
}
// Return memory size
ct->taken -= found->second;
ct->allocs.erase(found);
return CELL_OK;
}
}
if (!Memory.Free(addr))
{
return CELL_EINVAL; return CELL_EINVAL;
}
return CELL_OK; return CELL_OK;
} }
s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr) s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr)
{ {
sys_memory.Warning("sys_memory_get_page_attribute(addr=0x%x, attr_addr=0x%x)", addr, attr.addr()); sys_memory.Error("sys_memory_get_page_attribute(addr=0x%x, attr=*0x%x)", addr, attr);
LV2_LOCK;
// TODO: Implement per thread page attribute setting. // TODO: Implement per thread page attribute setting.
attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE
@ -105,26 +206,59 @@ s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr)
s32 sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info) s32 sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info)
{ {
sys_memory.Warning("sys_memory_get_user_memory_size(mem_info_addr=0x%x)", mem_info.addr()); sys_memory.Warning("sys_memory_get_user_memory_size(mem_info=*0x%x)", mem_info);
LV2_LOCK;
u32 reserved = 0;
u32 available = 0;
// Check all memory containers
for (auto& ct : Emu.GetIdManager().get_all<lv2_memory_container_t>())
{
reserved += ct->size;
available += ct->size - ct->taken;
}
// Fetch the user memory available
mem_info->total_user_memory = Memory.GetUserMemTotalSize() - reserved;
mem_info->available_user_memory = Memory.GetUserMemAvailSize() - available;
// Fetch the user memory available.
mem_info->total_user_memory = Memory.GetUserMemTotalSize();
mem_info->available_user_memory = Memory.GetUserMemAvailSize();
return CELL_OK; return CELL_OK;
} }
s32 sys_memory_container_create(vm::ptr<u32> cid, u32 yield_size) s32 sys_memory_container_create(vm::ptr<u32> cid, u32 size)
{ {
sys_memory.Warning("sys_memory_container_create(cid_addr=0x%x, yield_size=0x%x)", cid.addr(), yield_size); sys_memory.Warning("sys_memory_container_create(cid=*0x%x, size=0x%x)", cid, size);
yield_size &= ~0xfffff; //round down to 1 MB granularity LV2_LOCK;
u32 addr = (u32)Memory.Alloc(yield_size, 0x100000); //1 MB alignment
if(!addr) // Round down to 1 MB granularity
size &= ~0xfffff;
if (!size)
{
return CELL_ENOMEM; return CELL_ENOMEM;
}
// Wrap the allocated memory in a memory container. u32 reserved = 0;
*cid = Emu.GetIdManager().make<MemoryContainerInfo>(addr, yield_size); u32 available = 0;
// Check all memory containers
for (auto& ct : Emu.GetIdManager().get_all<lv2_memory_container_t>())
{
reserved += ct->size;
available += ct->size - ct->taken;
}
if (Memory.GetUserMemTotalSize() < reserved + size ||
Memory.GetUserMemAvailSize() < available + size)
{
return CELL_ENOMEM;
}
// Create the memory container
*cid = Emu.GetIdManager().make<lv2_memory_container_t>(size);
return CELL_OK; return CELL_OK;
} }
@ -133,35 +267,41 @@ s32 sys_memory_container_destroy(u32 cid)
{ {
sys_memory.Warning("sys_memory_container_destroy(cid=0x%x)", cid); sys_memory.Warning("sys_memory_container_destroy(cid=0x%x)", cid);
// Check if this container ID is valid. LV2_LOCK;
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid);
const auto ct = Emu.GetIdManager().get<lv2_memory_container_t>(cid);
if (!ct) if (!ct)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// Release the allocated memory and remove the ID. // Check if some memory is not deallocated (the container cannot be destroyed in this case)
Memory.Free(ct->addr); if (ct->taken)
Emu.GetIdManager().remove<MemoryContainerInfo>(cid); {
return CELL_EBUSY;
}
Emu.GetIdManager().remove<lv2_memory_container_t>(cid);
return CELL_OK; return CELL_OK;
} }
s32 sys_memory_container_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid) s32 sys_memory_container_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid)
{ {
sys_memory.Warning("sys_memory_container_get_size(mem_info_addr=0x%x, cid=0x%x)", mem_info.addr(), cid); sys_memory.Warning("sys_memory_container_get_size(mem_info=*0x%x, cid=0x%x)", mem_info, cid);
// Check if this container ID is valid. LV2_LOCK;
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid);
const auto ct = Emu.GetIdManager().get<lv2_memory_container_t>(cid);
if (!ct) if (!ct)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// HACK: Return all memory. mem_info->total_user_memory = ct->size; // total container memory
mem_info->total_user_memory = ct->size; mem_info->available_user_memory = ct->size - ct->taken; // available container memory
mem_info->available_user_memory = ct->size;
return CELL_OK; return CELL_OK;
} }

View file

@ -20,10 +20,11 @@ enum : u64
SYS_MEMORY_ATTR_READ_WRITE = 0x0000000000040000ULL, SYS_MEMORY_ATTR_READ_WRITE = 0x0000000000040000ULL,
}; };
enum enum : u64
{ {
SYS_MEMORY_PAGE_SIZE_1M = 0x400, SYS_MEMORY_PAGE_SIZE_1M = 0x400ull,
SYS_MEMORY_PAGE_SIZE_64K = 0x200, SYS_MEMORY_PAGE_SIZE_64K = 0x200ull,
SYS_MEMORY_PAGE_SIZE_MASK = 0xf00ull,
}; };
struct sys_memory_info_t struct sys_memory_info_t
@ -41,24 +42,26 @@ struct sys_page_attr_t
be_t<u32> pad; be_t<u32> pad;
}; };
struct MemoryContainerInfo struct lv2_memory_container_t
{ {
u32 addr; const u32 size; // amount of "physical" memory in this container
u32 size; const u32 id;
MemoryContainerInfo(u32 addr, u32 size) // amount of memory allocated
: addr(addr) std::atomic<u32> taken{ 0 };
, size(size)
{ // allocations (addr -> size)
} std::map<u32, u32> allocs;
lv2_memory_container_t(u32 size);
}; };
// SysCalls // SysCalls
s32 sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr); s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr);
s32 sys_memory_allocate_from_container(u32 size, u32 cid, u32 flags, u32 alloc_addr_addr); s32 sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr);
s32 sys_memory_free(u32 start_addr); s32 sys_memory_free(u32 start_addr);
s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr); s32 sys_memory_get_page_attribute(u32 addr, vm::ptr<sys_page_attr_t> attr);
s32 sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info); s32 sys_memory_get_user_memory_size(vm::ptr<sys_memory_info_t> mem_info);
s32 sys_memory_container_create(vm::ptr<u32> cid, u32 yield_size); s32 sys_memory_container_create(vm::ptr<u32> cid, u32 size);
s32 sys_memory_container_destroy(u32 cid); s32 sys_memory_container_destroy(u32 cid);
s32 sys_memory_container_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid); s32 sys_memory_container_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid);

View file

@ -4,91 +4,133 @@
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "sys_memory.h"
#include "sys_mmapper.h" #include "sys_mmapper.h"
#include <map>
SysCallBase sys_mmapper("sys_mmapper"); SysCallBase sys_mmapper("sys_mmapper");
std::map<u32, u32> mmapper_info_map;
s32 sys_mmapper_allocate_address(u32 size, u64 flags, u32 alignment, u32 alloc_addr) lv2_memory_t::lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr<lv2_memory_container_t> ct)
: size(size)
, align(align)
, id(Emu.GetIdManager().get_current_id())
, flags(flags)
, ct(ct)
{ {
sys_mmapper.Warning("sys_mmapper_allocate_address(size=0x%x, flags=0x%llx, alignment=0x%x, alloc_addr=0x%x)", }
size, flags, alignment, alloc_addr);
// Check for valid alignment. s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
if(alignment > 0x80000000) {
return CELL_EALIGN; sys_mmapper.Error("sys_mmapper_allocate_address(size=0x%llx, flags=0x%llx, alignment=0x%llx, alloc_addr=*0x%x)", size, flags, alignment, alloc_addr);
// Check page size. LV2_LOCK;
u32 addr;
switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K)) if (size % 0x10000000)
{ {
default:
case SYS_MEMORY_PAGE_SIZE_1M:
if(align(size, alignment) & 0xfffff)
return CELL_EALIGN; return CELL_EALIGN;
addr = (u32)Memory.Alloc(size, 0x100000);
break;
case SYS_MEMORY_PAGE_SIZE_64K:
if (align(size, alignment) & 0xffff)
return CELL_EALIGN;
addr = (u32)Memory.Alloc(size, 0x10000);
break;
} }
// Write back the start address of the allocated area. if (size > UINT32_MAX)
vm::write32(alloc_addr, addr); {
return CELL_ENOMEM;
}
switch (alignment)
{
case 0x10000000:
case 0x20000000:
case 0x40000000:
case 0x80000000:
{
for (u32 addr = ::align(0x30000000, alignment); addr < 0xC0000000; addr += static_cast<u32>(alignment))
{
if (Memory.Map(addr, static_cast<u32>(size)))
{
*alloc_addr = addr;
return CELL_OK; return CELL_OK;
}
}
return CELL_ENOMEM;
}
}
return CELL_EALIGN;
} }
s32 sys_mmapper_allocate_fixed_address() s32 sys_mmapper_allocate_fixed_address()
{ {
sys_mmapper.Warning("sys_mmapper_allocate_fixed_address"); sys_mmapper.Error("sys_mmapper_allocate_fixed_address()");
// Allocate a fixed size from user memory. LV2_LOCK;
if (!Memory.Alloc(SYS_MMAPPER_FIXED_SIZE, 0x100000))
if (!Memory.Map(0xB0000000, 0x10000000))
{
return CELL_EEXIST; return CELL_EEXIST;
}
return CELL_OK; return CELL_OK;
} }
s32 sys_mmapper_allocate_memory(u32 size, u64 flags, vm::ptr<u32> mem_id) // Allocate physical memory (create lv2_memory_t object)
s32 sys_mmapper_allocate_memory(u64 size, u64 flags, vm::ptr<u32> mem_id)
{ {
sys_mmapper.Warning("sys_mmapper_allocate_memory(size=0x%x, flags=0x%llx, mem_id_addr=0x%x)", size, flags, mem_id.addr()); sys_mmapper.Warning("sys_mmapper_allocate_memory(size=0x%llx, flags=0x%llx, mem_id=*0x%x)", size, flags, mem_id);
// Check page granularity. LV2_LOCK;
switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
// Check page granularity
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
{ {
case SYS_MEMORY_PAGE_SIZE_1M: case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) {
if (size % 0x100000)
{
return CELL_EALIGN; return CELL_EALIGN;
break;
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff)
return CELL_EALIGN;
break;
default:
return CELL_EINVAL;
} }
// Generate a new mem ID. break;
*mem_id = Emu.GetIdManager().make<mmapper_info>(size, flags); }
case SYS_MEMORY_PAGE_SIZE_64K:
{
if (size % 0x10000)
{
return CELL_EALIGN;
}
break;
}
default:
{
return CELL_EINVAL;
}
}
if (size > UINT32_MAX)
{
return CELL_ENOMEM;
}
const u32 align =
flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 :
flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 :
throw EXCEPTION("Unexpected");
// Generate a new mem ID
*mem_id = Emu.GetIdManager().make<lv2_memory_t>(static_cast<u32>(size), align, flags, nullptr);
return CELL_OK; return CELL_OK;
} }
s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id) s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id)
{ {
sys_mmapper.Warning("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id_addr=0x%x)", sys_mmapper.Error("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=0x%x, flags=0x%llx, mem_id=*0x%x)", size, cid, flags, mem_id);
size, cid, flags, mem_id.addr());
LV2_LOCK;
// Check if this container ID is valid. // Check if this container ID is valid.
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid); const auto ct = Emu.GetIdManager().get<lv2_memory_container_t>(cid);
if (!ct) if (!ct)
{ {
@ -96,143 +138,224 @@ s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm:
} }
// Check page granularity. // Check page granularity.
switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K)) switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
{ {
case SYS_MEMORY_PAGE_SIZE_1M: case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) {
if (size % 0x100000)
{
return CELL_EALIGN; return CELL_EALIGN;
}
break; break;
}
case SYS_MEMORY_PAGE_SIZE_64K: case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff) {
if (size % 0x10000)
{
return CELL_EALIGN; return CELL_EALIGN;
}
break; break;
}
default: default:
{
return CELL_EINVAL;
}
}
if (ct->size - ct->taken < size)
{
return CELL_ENOMEM;
}
const u32 align =
flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 :
flags & SYS_MEMORY_PAGE_SIZE_64K ? 0x10000 :
throw EXCEPTION("Unexpected");
ct->taken += size;
// Generate a new mem ID
*mem_id = Emu.GetIdManager().make<lv2_memory_t>(size, align, flags, ct);
return CELL_OK;
}
s32 sys_mmapper_change_address_access_right(u32 addr, u64 flags)
{
sys_mmapper.Todo("sys_mmapper_change_address_access_right(addr=0x%x, flags=0x%llx)", addr, flags);
return CELL_OK;
}
s32 sys_mmapper_free_address(u32 addr)
{
sys_mmapper.Error("sys_mmapper_free_address(addr=0x%x)", addr);
LV2_LOCK;
const auto area = Memory.Get(addr);
if (!area)
{
return CELL_EINVAL; return CELL_EINVAL;
} }
ct->size = size; if (area->GetUsedSize())
{
return CELL_EBUSY;
}
// Generate a new mem ID. if (Memory.Unmap(addr))
*mem_id = Emu.GetIdManager().make<mmapper_info>(ct->size, flags); {
throw EXCEPTION("Unexpected (failed to unmap memory ad 0x%x)", addr);
}
return CELL_OK; return CELL_OK;
} }
s32 sys_mmapper_change_address_access_right(u32 start_addr, u64 flags)
{
sys_mmapper.Warning("sys_mmapper_change_address_access_right(start_addr=0x%x, flags=0x%llx)", start_addr, flags);
// TODO
return CELL_OK;
}
s32 sys_mmapper_free_address(u32 start_addr)
{
sys_mmapper.Warning("sys_mmapper_free_address(start_addr=0x%x)", start_addr);
// Free the address.
Memory.Free(start_addr);
return CELL_OK;
}
s32 sys_mmapper_free_memory(u32 mem_id) s32 sys_mmapper_free_memory(u32 mem_id)
{ {
sys_mmapper.Warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id); sys_mmapper.Warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id);
// Check if this mem ID is valid. LV2_LOCK;
const auto info = Emu.GetIdManager().get<mmapper_info>(mem_id);
if (!info) // Check if this mem ID is valid.
const auto mem = Emu.GetIdManager().get<lv2_memory_t>(mem_id);
if (!mem)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// Release the allocated memory and remove the ID. if (mem->addr)
Emu.GetIdManager().remove<mmapper_info>(mem_id); {
return CELL_EBUSY;
}
// Return physical memory to the container if necessary
if (mem->ct)
{
mem->ct->taken -= mem->size;
}
// Release the allocated memory and remove the ID
Emu.GetIdManager().remove<lv2_memory_t>(mem_id);
return CELL_OK; return CELL_OK;
} }
s32 sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags) s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags)
{ {
sys_mmapper.Warning("sys_mmapper_map_memory(start_addr=0x%x, mem_id=0x%x, flags=0x%llx)", start_addr, mem_id, flags); sys_mmapper.Error("sys_mmapper_map_memory(addr=0x%x, mem_id=0x%x, flags=0x%llx)", addr, mem_id, flags);
// Check if this mem ID is valid. LV2_LOCK;
const auto info = Emu.GetIdManager().get<mmapper_info>(mem_id);
if (!info) const auto area = Memory.Get(addr & 0xf0000000);
if (!area || addr < 0x30000000 || addr >= 0xC0000000)
{
return CELL_EINVAL;
}
const auto mem = Emu.GetIdManager().get<lv2_memory_t>(mem_id);
if (!mem)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// Map the memory into the process address. if (addr % mem->align)
if(!Memory.Map(start_addr, info->size)) {
sys_mmapper.Error("sys_mmapper_map_memory failed!"); return CELL_EALIGN;
}
// Keep track of mapped addresses. if (mem->addr)
mmapper_info_map[start_addr] = mem_id; {
throw EXCEPTION("Already mapped (mem_id=0x%x, addr=0x%x)", mem_id, mem->addr.load());
}
if (!area->AllocFixed(addr, mem->size))
{
return CELL_EBUSY;
}
mem->addr = addr;
return CELL_OK; return CELL_OK;
} }
s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, u32 alloc_addr) s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr<u32> alloc_addr)
{ {
sys_mmapper.Warning("sys_mmapper_search_and_map(start_addr=0x%x, mem_id=0x%x, flags=0x%llx, alloc_addr=0x%x)", sys_mmapper.Error("sys_mmapper_search_and_map(start_addr=0x%x, mem_id=0x%x, flags=0x%llx, alloc_addr=*0x%x)", start_addr, mem_id, flags, alloc_addr);
start_addr, mem_id, flags, alloc_addr);
// Check if this mem ID is valid. LV2_LOCK;
const auto info = Emu.GetIdManager().get<mmapper_info>(mem_id);
if (!info) const auto area = Memory.Get(start_addr);
if (!area || start_addr < 0x30000000 || start_addr >= 0xC0000000)
{
return CELL_EINVAL;
}
const auto mem = Emu.GetIdManager().get<lv2_memory_t>(mem_id);
if (!mem)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// Search for a mappable address. const u32 addr = area->AllocAlign(mem->size, mem->align);
u32 addr;
bool found;
for (int i = 0; i < SYS_MMAPPER_FIXED_SIZE; i += 0x100000)
{
addr = start_addr + i;
found = Memory.Map(addr, info->size);
if(found)
{
sys_mmapper.Warning("Found and mapped address 0x%x", addr);
break;
}
}
if (!found) if (!addr)
{
return CELL_ENOMEM; return CELL_ENOMEM;
}
// Write back the start address of the allocated area. *alloc_addr = addr;
vm::write32(alloc_addr, addr);
// Keep track of mapped addresses. return CELL_ENOMEM;
mmapper_info_map[addr] = mem_id;
return CELL_OK;
} }
s32 sys_mmapper_unmap_memory(u32 start_addr, u32 mem_id_addr) s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id)
{ {
sys_mmapper.Warning("sys_mmapper_unmap_memory(start_addr=0x%x, mem_id_addr=0x%x)", start_addr, mem_id_addr); sys_mmapper.Todo("sys_mmapper_unmap_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id);
// Write back the mem ID of the unmapped area. LV2_LOCK;
u32 mem_id = mmapper_info_map.find(start_addr)->second;
vm::write32(mem_id_addr, mem_id); const auto area = Memory.Get(addr);
if (!area || addr < 0x30000000 || addr >= 0xC0000000)
{
return CELL_EINVAL;
}
for (auto& mem : Emu.GetIdManager().get_all<lv2_memory_t>())
{
if (mem->addr == addr)
{
if (!area->Free(addr))
{
throw EXCEPTION("Not mapped (mem_id=0x%x, addr=0x%x)", mem->id, addr);
}
mem->addr = 0;
*mem_id = mem->id;
return CELL_OK; return CELL_OK;
}
}
return CELL_EINVAL;
} }
s32 sys_mmapper_enable_page_fault_notification(u32 start_addr, u32 q_id) s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq)
{ {
sys_mmapper.Warning("sys_mmapper_enable_page_fault_notification(start_addr=0x%x, q_id=0x%x)", start_addr, q_id); sys_mmapper.Todo("sys_mmapper_enable_page_fault_notification(addr=0x%x, eq=0x%x)", addr, eq);
// TODO
return CELL_OK; return CELL_OK;
} }

View file

@ -1,37 +1,33 @@
#pragma once #pragma once
#include "sys_memory.h"
namespace vm { using namespace ps3; } namespace vm { using namespace ps3; }
#define SYS_MMAPPER_FIXED_ADDR 0xB0000000 struct lv2_memory_t
#define SYS_MMAPPER_FIXED_SIZE 0x10000000
struct mmapper_info
{ {
u32 size; const u32 size; // memory size
u64 flags; const u32 align; // required alignment
const u32 id;
const u64 flags;
const std::shared_ptr<lv2_memory_container_t> ct; // memory container the physical memory is taken from
mmapper_info(u32 _size, u64 _flags) std::atomic<u32> addr{ 0 }; // actual mapping address
: size(_size)
, flags(_flags)
{
}
mmapper_info() lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr<lv2_memory_container_t> ct);
{
}
}; };
REG_ID_TYPE(mmapper_info, 0x08); // SYS_MEM_OBJECT REG_ID_TYPE(lv2_memory_t, 0x08); // SYS_MEM_OBJECT
// SysCalls // SysCalls
s32 sys_mmapper_allocate_address(u32 size, u64 flags, u32 alignment, u32 alloc_addr); s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr);
s32 sys_mmapper_allocate_fixed_address(); s32 sys_mmapper_allocate_fixed_address();
s32 sys_mmapper_allocate_memory(u32 size, u64 flags, vm::ptr<u32> mem_id); s32 sys_mmapper_allocate_memory(u64 size, u64 flags, vm::ptr<u32> mem_id);
s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id); s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm::ptr<u32> mem_id);
s32 sys_mmapper_change_address_access_right(u32 start_addr, u64 flags); s32 sys_mmapper_change_address_access_right(u32 addr, u64 flags);
s32 sys_mmapper_free_address(u32 start_addr); s32 sys_mmapper_free_address(u32 addr);
s32 sys_mmapper_free_memory(u32 mem_id); s32 sys_mmapper_free_memory(u32 mem_id);
s32 sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags); s32 sys_mmapper_map_memory(u32 addr, u32 mem_id, u64 flags);
s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, u32 alloc_addr); s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, vm::ptr<u32> alloc_addr);
s32 sys_mmapper_unmap_memory(u32 start_addr, u32 mem_id_addr); s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id);
s32 sys_mmapper_enable_page_fault_notification(u32 start_addr, u32 q_id); s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq);

View file

@ -1311,7 +1311,7 @@ s32 sys_raw_spu_set_spu_cfg(u32 id, u32 value)
if (value > 3) if (value > 3)
{ {
sys_spu.Fatal("sys_raw_spu_set_spu_cfg(id=%d, value=0x%x)", id, value); throw EXCEPTION("Unexpected value (0x%x)", value);
} }
const auto thread = Emu.GetCPU().GetRawSPUThread(id); const auto thread = Emu.GetCPU().GetRawSPUThread(id);

View file

@ -8,55 +8,24 @@
#include "sys_vm.h" #include "sys_vm.h"
SysCallBase sys_vm("sys_vm"); SysCallBase sys_vm("sys_vm");
std::shared_ptr<MemoryContainerInfo> current_ct;
s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, u32 addr) s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
{ {
sys_vm.Error("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%llx, policy=0x%llx, addr_addr=0x%x)", sys_vm.Error("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%llx, policy=0x%llx, addr=*0x%x)", vsize, psize, cid, flag, policy, addr);
vsize, psize, cid, flag, policy, addr);
// Check virtual size. LV2_LOCK;
if((vsize < (0x100000 * 32)) || (vsize > (0x100000 * 256)))
{
return CELL_EINVAL;
}
// Check physical size.
if(psize > (0x100000 * 256))
{
return CELL_ENOMEM;
}
// Use fixed address (TODO: search and use some free address instead) // Use fixed address (TODO: search and use some free address instead)
u32 new_addr = vm::check_addr(0x60000000) ? 0x70000000 : 0x60000000; const u32 new_addr = vm::check_addr(0x60000000) ? 0x70000000 : 0x60000000;
// If container ID is SYS_MEMORY_CONTAINER_ID_INVALID, allocate directly. // Map memory
if(cid == SYS_MEMORY_CONTAINER_ID_INVALID)
{
// Create a new MemoryContainerInfo to act as default container with vsize.
current_ct.reset(new MemoryContainerInfo(new_addr, vsize));
}
else
{
// Check memory container.
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid);
if (!ct)
{
return CELL_ESRCH;
}
current_ct = ct;
}
// Allocate actual memory using virtual size (physical size is ignored)
if (!Memory.Map(new_addr, vsize)) if (!Memory.Map(new_addr, vsize))
{ {
return CELL_ENOMEM; return CELL_ENOMEM;
} }
// Write a pointer for the allocated memory. // Write a pointer for the allocated memory.
vm::write32(addr, new_addr); *addr = new_addr;
return CELL_OK; return CELL_OK;
} }
@ -65,211 +34,99 @@ s32 sys_vm_unmap(u32 addr)
{ {
sys_vm.Error("sys_vm_unmap(addr=0x%x)", addr); sys_vm.Error("sys_vm_unmap(addr=0x%x)", addr);
// Unmap memory. LV2_LOCK;
assert(addr == 0x60000000 || addr == 0x70000000);
if(!Memory.Unmap(addr)) return CELL_EINVAL; if (!Memory.Unmap(addr))
{
return CELL_EINVAL;
}
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_append_memory(u32 addr, u32 size) s32 sys_vm_append_memory(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_append_memory(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_append_memory(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (size <= 0))
{
return CELL_EINVAL;
}
// Total memory size must not be superior to 256MB.
if((current_ct->size + size) > (0x100000 * 256))
{
return CELL_ENOMEM;
}
// The size is added to the virtual size, which should be inferior to the physical size allocated.
current_ct->size += size;
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_return_memory(u32 addr, u32 size) s32 sys_vm_return_memory(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_return_memory(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_return_memory(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (size <= 0))
{
return CELL_EINVAL;
}
// The memory size to return should not be superior to the virtual size in use minus 1MB.
if(current_ct->size < (size + 0x100000))
{
return CELL_EBUSY;
}
// The size is returned to physical memory and is subtracted to the virtual size.
current_ct->size -= size;
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_lock(u32 addr, u32 size) s32 sys_vm_lock(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_lock(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_lock(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// The memory size to return should not be superior to the virtual size to lock minus 1MB.
if(current_ct->size < (size + 0x100000))
{
return CELL_EBUSY;
}
// TODO: The locked memory area keeps allocated and unchanged until sys_vm_unlocked is called.
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_unlock(u32 addr, u32 size) s32 sys_vm_unlock(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_unlock(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_unlock(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// TODO: Unlock
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_touch(u32 addr, u32 size) s32 sys_vm_touch(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_touch(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_touch(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// TODO
// sys_vm_touch allocates physical memory for a virtual memory address.
// This function is asynchronous, so it may not complete immediately.
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_flush(u32 addr, u32 size) s32 sys_vm_flush(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_flush(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_flush(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// TODO
// sys_vm_flush frees physical memory for a virtual memory address and creates a backup if the memory area is dirty.
// This function is asynchronous, so it may not complete immediately.
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_invalidate(u32 addr, u32 size) s32 sys_vm_invalidate(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_invalidate(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_invalidate(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// TODO
// sys_vm_invalidate frees physical memory for a virtual memory address.
// This function is asynchronous, so it may not complete immediately.
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_store(u32 addr, u32 size) s32 sys_vm_store(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_store(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_store(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// TODO
// sys_vm_store creates a backup for a dirty virtual memory area and marks it as clean.
// This function is asynchronous, so it may not complete immediately.
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_sync(u32 addr, u32 size) s32 sys_vm_sync(u32 addr, u32 size)
{ {
sys_vm.Todo("sys_vm_sync(addr=0x%x,size=0x%x)", addr, size); sys_vm.Todo("sys_vm_sync(addr=0x%x, size=0x%x)", addr, size);
// Check address and size.
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// TODO
// sys_vm_sync stalls execution until all asynchronous vm calls finish.
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_test(u32 addr, u32 size, vm::ptr<u64> result) s32 sys_vm_test(u32 addr, u32 size, vm::ptr<u64> result)
{ {
sys_vm.Todo("sys_vm_test(addr=0x%x, size=0x%x, result_addr=0x%x)", addr, size, result.addr()); sys_vm.Todo("sys_vm_test(addr=0x%x, size=0x%x, result=*0x%x)", addr, size, result);
// Check address and size. *result = SYS_VM_STATE_ON_MEMORY;
if((current_ct->addr != addr) || (current_ct->size < size) || (size <= 0))
{
return CELL_EINVAL;
}
// TODO
// sys_vm_test checks the state of a portion of the virtual memory area.
// Faking.
*result = SYS_VM_TEST_ALLOCATED;
return CELL_OK; return CELL_OK;
} }
s32 sys_vm_get_statistics(u32 addr, vm::ptr<sys_vm_statistics> stat) s32 sys_vm_get_statistics(u32 addr, vm::ptr<sys_vm_statistics_t> stat)
{ {
sys_vm.Todo("sys_vm_get_statistics(addr=0x%x, stat_addr=0x%x)", addr, stat.addr()); sys_vm.Todo("sys_vm_get_statistics(addr=0x%x, stat=*0x%x)", addr, stat);
// Check address.
if(current_ct->addr != addr)
{
return CELL_EINVAL;
}
// TODO
stat->page_fault_ppu = 0; stat->page_fault_ppu = 0;
stat->page_fault_spu = 0; stat->page_fault_spu = 0;
stat->page_in = 0; stat->page_in = 0;
stat->page_out = 0; stat->page_out = 0;
stat->pmem_total = current_ct->size; stat->pmem_total = 0;
stat->pmem_used = 0; stat->pmem_used = 0;
stat->timestamp = 0; stat->timestamp = 0;
return CELL_OK; return CELL_OK;
} }

View file

@ -4,13 +4,13 @@ namespace vm { using namespace ps3; }
enum : u64 enum : u64
{ {
SYS_VM_TEST_INVALID = 0, SYS_VM_STATE_INVALID = 0ull,
SYS_VM_TEST_UNUSED = 1, SYS_VM_STATE_UNUSED = 1ull,
SYS_VM_TEST_ALLOCATED = 2, SYS_VM_STATE_ON_MEMORY = 2ull,
SYS_VM_TEST_STORED = 4, SYS_VM_STATE_STORED = 4ull,
}; };
struct sys_vm_statistics struct sys_vm_statistics_t
{ {
be_t<u64> page_fault_ppu; // Number of bad virtual memory accesses from a PPU thread. be_t<u64> page_fault_ppu; // Number of bad virtual memory accesses from a PPU thread.
be_t<u64> page_fault_spu; // Number of bad virtual memory accesses from a SPU thread. be_t<u64> page_fault_spu; // Number of bad virtual memory accesses from a SPU thread.
@ -22,7 +22,7 @@ struct sys_vm_statistics
}; };
// SysCalls // SysCalls
s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, u32 addr); s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
s32 sys_vm_unmap(u32 addr); s32 sys_vm_unmap(u32 addr);
s32 sys_vm_append_memory(u32 addr, u32 size); s32 sys_vm_append_memory(u32 addr, u32 size);
s32 sys_vm_return_memory(u32 addr, u32 size); s32 sys_vm_return_memory(u32 addr, u32 size);
@ -34,4 +34,4 @@ s32 sys_vm_invalidate(u32 addr, u32 size);
s32 sys_vm_store(u32 addr, u32 size); s32 sys_vm_store(u32 addr, u32 size);
s32 sys_vm_sync(u32 addr, u32 size); s32 sys_vm_sync(u32 addr, u32 size);
s32 sys_vm_test(u32 addr, u32 size, vm::ptr<u64> result); s32 sys_vm_test(u32 addr, u32 size, vm::ptr<u64> result);
s32 sys_vm_get_statistics(u32 addr, vm::ptr<sys_vm_statistics> stat); s32 sys_vm_get_statistics(u32 addr, vm::ptr<sys_vm_statistics_t> stat);

View file

@ -120,7 +120,9 @@ MainFrame::MainFrame()
menu_help->Append(id_help_about, "&About..."); menu_help->Append(id_help_about, "&About...");
SetMenuBar(menubar); SetMenuBar(menubar);
#ifdef _WIN32
SetIcon(wxICON(frame_icon)); SetIcon(wxICON(frame_icon));
#endif
// Panels // Panels
m_log_frame = new LogFrame(this); m_log_frame = new LogFrame(this);

View file

@ -95,30 +95,30 @@ struct explicit_bool_t
}; };
// return 32 bit sizeof() to avoid widening/narrowing conversions with size_t // return 32 bit sizeof() to avoid widening/narrowing conversions with size_t
#define sizeof32(type) sizeof32_t<sizeof(type)>::value #define sizeof32(type) static_cast<u32>(sizeof32_t<sizeof(type)>::value)
// return 32 bit alignof() to avoid widening/narrowing conversions with size_t // return 32 bit alignof() to avoid widening/narrowing conversions with size_t
#define alignof32(type) alignof32_t<__alignof(type)>::value #define alignof32(type) static_cast<u32>(alignof32_t<__alignof(type)>::value)
template<std::size_t Size> struct sizeof32_t template<std::size_t Size> struct sizeof32_t
{ {
static_assert(Size <= UINT32_MAX, "sizeof32() error: size is too big"); static_assert(Size <= UINT32_MAX, "sizeof32() error: size is too big");
static const u32 value = static_cast<u32>(Size); enum : u32 { value = static_cast<u32>(Size) };
}; };
template<std::size_t Align> struct alignof32_t template<std::size_t Align> struct alignof32_t
{ {
static_assert(Align <= UINT32_MAX, "alignof32() error: alignment is too big"); static_assert(Align <= UINT32_MAX, "alignof32() error: alignment is too big");
static const u32 value = static_cast<u32>(Align); enum : u32 { value = static_cast<u32>(Align) };
}; };
template<typename T> using func_def = T; // workaround for MSVC bug: `using X = func_def<void()>;` instead of `using X = void();` template<typename T> using func_def = T; // workaround for MSVC bug: `using X = func_def<void()>;` instead of `using X = void();`
template<typename T> struct ID_type; template<typename T> struct ID_type;
#define REG_ID_TYPE(t, id) template<> struct ID_type<t> { static const u32 type = id; } #define REG_ID_TYPE(t, id) template<> struct ID_type<t> { enum : u32 { type = id }; }
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size") #define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size")
#define CHECK_ALIGN(type, align) static_assert(__alignof(type) == align, "Invalid " #type " type alignment") #define CHECK_ALIGN(type, align) static_assert(__alignof(type) == align, "Invalid " #type " type alignment")