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

@ -3292,10 +3292,10 @@ void Compiler::MFSPR(u32 rd, u32 spr) {
rd_i64 = GetVrsave();
break;
case 0x10C:
rd_i64 = Call<u64>("get_timebased_time", get_timebased_time);
rd_i64 = Call<u64>("get_timebased_time", get_timebased_time);
break;
case 0x10D:
rd_i64 = Call<u64>("get_timebased_time", get_timebased_time);
rd_i64 = Call<u64>("get_timebased_time", get_timebased_time);
rd_i64 = m_ir_builder->CreateLShr(rd_i64, 32);
break;
default:
@ -3340,7 +3340,7 @@ void Compiler::LVXL(u32 vd, u32 ra, u32 rb) {
}
void Compiler::MFTB(u32 rd, u32 spr) {
auto tb_i64 = Call<u64>("get_timebased_time", get_timebased_time);
auto tb_i64 = Call<u64>("get_timebased_time", get_timebased_time);
u32 n = (spr >> 5) | ((spr & 0x1f) << 5);
if (n == 0x10D) {

View File

@ -9,16 +9,16 @@
thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
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()
{
join();
Memory.Unmap(offset);
vm::page_unmap(offset, 0x40000);
}
void RawSPUThread::start()

View File

@ -66,10 +66,26 @@ void MemoryBase::Close()
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);
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++)
{
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;
}
@ -97,9 +112,25 @@ bool MemoryBase::Unmap(const u32 addr)
return true;
}
}
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)
: MemInfo(addr, size)
{

View File

@ -28,7 +28,8 @@ public:
{
DynamicMemoryBlock RAM;
DynamicMemoryBlock Userspace;
} PSV;
}
PSV;
struct
{
@ -37,7 +38,8 @@ public:
DynamicMemoryBlock RAM;
DynamicMemoryBlock Kernel;
DynamicMemoryBlock Userspace;
} PSP;
}
PSP;
bool m_inited;
@ -51,10 +53,6 @@ public:
Close();
}
void RegisterPages(u32 addr, u32 size);
void UnregisterPages(u32 addr, u32 size);
void Init(MemoryType type);
void Close();
@ -82,6 +80,8 @@ public:
bool Map(const u32 addr, const u32 size);
bool Unmap(const u32 addr);
MemoryBlock* Get(const u32 addr);
};
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 LogSuccess: LOG_SUCCESS(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 LogFatal: throw EXCEPTION("%s error: %s", GetName().c_str(), text.c_str());
}
}

View File

@ -11,7 +11,6 @@ class LogBase
LogSuccess,
LogWarning,
LogError,
LogFatal,
LogTodo,
};
@ -63,11 +62,6 @@ public:
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
{
LogPrepare(LogTodo, fmt, fmt::do_unveil(args)...);

View File

@ -777,7 +777,7 @@ s32 cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
}
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)
{
cellVdec.Fatal("cellVdecDecodeAu(): unsupported decoding mode (%d)", mode);
throw EXCEPTION("Unsupported decoding mode (%d)", mode);
}
// TODO: check info
@ -711,13 +711,13 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
default:
{
cellVdec.Fatal("cellVdecGetPicture: unknown formatType(%d)", type);
throw EXCEPTION("Unknown formatType(%d)", type);
}
}
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)
@ -733,7 +733,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
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)
{
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);
@ -924,7 +924,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
{
auto mp2 = vm::ptr<CellVdecMpeg2Info>::make(info.addr() + sizeof32(CellVdecPicItem));
cellVdec.Fatal("cellVdecGetPicItem(MPEG2)");
throw EXCEPTION("MPEG2");
}
*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)
{
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;
@ -301,7 +301,7 @@ s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
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)
{
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;
@ -619,14 +619,13 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
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;
}
sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): unexpected syscall result (0x%x)", lwcond, res);
return res;
throw EXCEPTION("Unexpected syscall result (lwcond=*0x%x, result=0x%x)", lwcond, res);
}
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);
// probably, assertion failed
sysPrxForUser.Fatal("_sys_printf: \n%s", fmt.get_ptr());
Emu.Pause();
return CELL_OK;
throw EXCEPTION("%s", fmt.get_ptr());
}
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)
{
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));

View File

@ -133,7 +133,7 @@ s32 _sys_lwmutex_unlock(u32 lwmutex_id)
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++;

View File

@ -5,95 +5,196 @@
#include "Emu/SysCalls/SysCalls.h"
#include "sys_memory.h"
#include <map>
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.
u32 addr;
}
s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_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)
{
case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) return CELL_EALIGN;
addr = (u32)Memory.Alloc(size, 0x100000);
break;
{
if (size % 0x100000)
{
return CELL_EALIGN;
}
break;
}
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff) return CELL_EALIGN;
addr = (u32)Memory.Alloc(size, 0x10000);
break;
{
if (size % 0x10000)
{
return CELL_EALIGN;
}
default: return CELL_EINVAL;
break;
}
if (!addr)
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.
sys_memory.Log("Memory allocated! [addr: 0x%x, size: 0x%x]", addr, size);
vm::write32(alloc_addr_addr, addr);
// Write back the start address of the allocated area
*alloc_addr = addr;
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.
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid);
LV2_LOCK;
// Check if this container ID is valid
const auto ct = Emu.GetIdManager().get<lv2_memory_container_t>(cid);
if (!ct)
{
return CELL_ESRCH;
}
// Check page size.
switch(flags)
// Check allocation size
switch (flags)
{
case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) return CELL_EALIGN;
ct->addr = (u32)Memory.Alloc(size, 0x100000);
break;
{
if (size % 0x100000)
{
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;
break;
}
// Store the address and size in the container.
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;
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.
sys_memory.Log("Memory allocated! [addr: 0x%x, size: 0x%x]", ct->addr, ct->size);
vm::write32(alloc_addr_addr, ct->addr);
*alloc_addr = addr;
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.
if(!Memory.Free(start_addr))
LV2_LOCK;
// 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_OK;
}
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.
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)
{
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();
mem_info->available_user_memory = Memory.GetUserMemAvailSize();
// Fetch the user memory available
mem_info->total_user_memory = Memory.GetUserMemTotalSize() - reserved;
mem_info->available_user_memory = Memory.GetUserMemAvailSize() - available;
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
u32 addr = (u32)Memory.Alloc(yield_size, 0x100000); //1 MB alignment
LV2_LOCK;
if(!addr)
// Round down to 1 MB granularity
size &= ~0xfffff;
if (!size)
{
return CELL_ENOMEM;
}
// Wrap the allocated memory in a memory container.
*cid = Emu.GetIdManager().make<MemoryContainerInfo>(addr, yield_size);
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;
}
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;
}
@ -133,35 +267,41 @@ s32 sys_memory_container_destroy(u32 cid)
{
sys_memory.Warning("sys_memory_container_destroy(cid=0x%x)", cid);
// Check if this container ID is valid.
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid);
LV2_LOCK;
const auto ct = Emu.GetIdManager().get<lv2_memory_container_t>(cid);
if (!ct)
{
return CELL_ESRCH;
}
// Release the allocated memory and remove the ID.
Memory.Free(ct->addr);
Emu.GetIdManager().remove<MemoryContainerInfo>(cid);
// Check if some memory is not deallocated (the container cannot be destroyed in this case)
if (ct->taken)
{
return CELL_EBUSY;
}
Emu.GetIdManager().remove<lv2_memory_container_t>(cid);
return CELL_OK;
}
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.
const auto ct = Emu.GetIdManager().get<MemoryContainerInfo>(cid);
LV2_LOCK;
const auto ct = Emu.GetIdManager().get<lv2_memory_container_t>(cid);
if (!ct)
{
return CELL_ESRCH;
}
// HACK: Return all memory.
mem_info->total_user_memory = ct->size;
mem_info->available_user_memory = ct->size;
mem_info->total_user_memory = ct->size; // total container memory
mem_info->available_user_memory = ct->size - ct->taken; // available container memory
return CELL_OK;
}

View File

@ -20,10 +20,11 @@ enum : u64
SYS_MEMORY_ATTR_READ_WRITE = 0x0000000000040000ULL,
};
enum
enum : u64
{
SYS_MEMORY_PAGE_SIZE_1M = 0x400,
SYS_MEMORY_PAGE_SIZE_64K = 0x200,
SYS_MEMORY_PAGE_SIZE_1M = 0x400ull,
SYS_MEMORY_PAGE_SIZE_64K = 0x200ull,
SYS_MEMORY_PAGE_SIZE_MASK = 0xf00ull,
};
struct sys_memory_info_t
@ -41,24 +42,26 @@ struct sys_page_attr_t
be_t<u32> pad;
};
struct MemoryContainerInfo
struct lv2_memory_container_t
{
u32 addr;
u32 size;
const u32 size; // amount of "physical" memory in this container
const u32 id;
MemoryContainerInfo(u32 addr, u32 size)
: addr(addr)
, size(size)
{
}
// amount of memory allocated
std::atomic<u32> taken{ 0 };
// allocations (addr -> size)
std::map<u32, u32> allocs;
lv2_memory_container_t(u32 size);
};
// SysCalls
s32 sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr);
s32 sys_memory_allocate_from_container(u32 size, u32 cid, 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, u64 flags, vm::ptr<u32> alloc_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_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_get_size(vm::ptr<sys_memory_info_t> mem_info, u32 cid);

View File

@ -4,91 +4,133 @@
#include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
#include "sys_memory.h"
#include "sys_mmapper.h"
#include <map>
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.
if(alignment > 0x80000000)
return CELL_EALIGN;
s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr<u32> alloc_addr)
{
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.
u32 addr;
switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
LV2_LOCK;
if (size % 0x10000000)
{
default:
case SYS_MEMORY_PAGE_SIZE_1M:
if(align(size, alignment) & 0xfffff)
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;
return CELL_EALIGN;
}
// Write back the start address of the allocated area.
vm::write32(alloc_addr, addr);
if (size > UINT32_MAX)
{
return CELL_ENOMEM;
}
return CELL_OK;
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_ENOMEM;
}
}
return CELL_EALIGN;
}
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.
if (!Memory.Alloc(SYS_MMAPPER_FIXED_SIZE, 0x100000))
LV2_LOCK;
if (!Memory.Map(0xB0000000, 0x10000000))
{
return CELL_EEXIST;
}
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.
switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
LV2_LOCK;
// Check page granularity
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
{
case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff)
{
if (size % 0x100000)
{
return CELL_EALIGN;
break;
}
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff)
return CELL_EALIGN;
break;
default:
return CELL_EINVAL;
break;
}
// Generate a new mem ID.
*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;
}
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)",
size, cid, flags, mem_id.addr());
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);
LV2_LOCK;
// 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)
{
@ -96,143 +138,224 @@ s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm:
}
// 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:
if(size & 0xfffff)
{
if (size % 0x100000)
{
return CELL_EALIGN;
break;
}
break;
}
case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff)
{
if (size % 0x10000)
{
return CELL_EALIGN;
break;
}
break;
}
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;
}
ct->size = size;
if (area->GetUsedSize())
{
return CELL_EBUSY;
}
// Generate a new mem ID.
*mem_id = Emu.GetIdManager().make<mmapper_info>(ct->size, flags);
if (Memory.Unmap(addr))
{
throw EXCEPTION("Unexpected (failed to unmap memory ad 0x%x)", addr);
}
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)
{
sys_mmapper.Warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id);
// Check if this mem ID is valid.
const auto info = Emu.GetIdManager().get<mmapper_info>(mem_id);
LV2_LOCK;
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;
}
// Release the allocated memory and remove the ID.
Emu.GetIdManager().remove<mmapper_info>(mem_id);
if (mem->addr)
{
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;
}
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.
const auto info = Emu.GetIdManager().get<mmapper_info>(mem_id);
LV2_LOCK;
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;
}
// Map the memory into the process address.
if(!Memory.Map(start_addr, info->size))
sys_mmapper.Error("sys_mmapper_map_memory failed!");
if (addr % mem->align)
{
return CELL_EALIGN;
}
// Keep track of mapped addresses.
mmapper_info_map[start_addr] = mem_id;
if (mem->addr)
{
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;
}
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)",
start_addr, mem_id, flags, alloc_addr);
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);
// Check if this mem ID is valid.
const auto info = Emu.GetIdManager().get<mmapper_info>(mem_id);
LV2_LOCK;
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;
}
// Search for a mappable address.
u32 addr;
bool found;
for (int i = 0; i < SYS_MMAPPER_FIXED_SIZE; i += 0x100000)
const u32 addr = area->AllocAlign(mem->size, mem->align);
if (!addr)
{
addr = start_addr + i;
found = Memory.Map(addr, info->size);
if(found)
return CELL_ENOMEM;
}
*alloc_addr = addr;
return CELL_ENOMEM;
}
s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_id)
{
sys_mmapper.Todo("sys_mmapper_unmap_memory(addr=0x%x, mem_id=*0x%x)", addr, mem_id);
LV2_LOCK;
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)
{
sys_mmapper.Warning("Found and mapped address 0x%x", addr);
break;
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;
}
}
if (!found)
return CELL_ENOMEM;
// Write back the start address of the allocated area.
vm::write32(alloc_addr, addr);
// Keep track of mapped addresses.
mmapper_info_map[addr] = mem_id;
return CELL_OK;
return CELL_EINVAL;
}
s32 sys_mmapper_unmap_memory(u32 start_addr, u32 mem_id_addr)
s32 sys_mmapper_enable_page_fault_notification(u32 addr, u32 eq)
{
sys_mmapper.Warning("sys_mmapper_unmap_memory(start_addr=0x%x, mem_id_addr=0x%x)", start_addr, mem_id_addr);
// Write back the mem ID of the unmapped area.
u32 mem_id = mmapper_info_map.find(start_addr)->second;
vm::write32(mem_id_addr, mem_id);
return CELL_OK;
}
s32 sys_mmapper_enable_page_fault_notification(u32 start_addr, u32 q_id)
{
sys_mmapper.Warning("sys_mmapper_enable_page_fault_notification(start_addr=0x%x, q_id=0x%x)", start_addr, q_id);
// TODO
sys_mmapper.Todo("sys_mmapper_enable_page_fault_notification(addr=0x%x, eq=0x%x)", addr, eq);
return CELL_OK;
}

View File

@ -1,37 +1,33 @@
#pragma once
#include "sys_memory.h"
namespace vm { using namespace ps3; }
#define SYS_MMAPPER_FIXED_ADDR 0xB0000000
#define SYS_MMAPPER_FIXED_SIZE 0x10000000
struct mmapper_info
struct lv2_memory_t
{
u32 size;
u64 flags;
const u32 size; // memory size
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)
: size(_size)
, flags(_flags)
{
}
std::atomic<u32> addr{ 0 }; // actual mapping address
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
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_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_change_address_access_right(u32 start_addr, u64 flags);
s32 sys_mmapper_free_address(u32 start_addr);
s32 sys_mmapper_change_address_access_right(u32 addr, u64 flags);
s32 sys_mmapper_free_address(u32 addr);
s32 sys_mmapper_free_memory(u32 mem_id);
s32 sys_mmapper_map_memory(u32 start_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_unmap_memory(u32 start_addr, u32 mem_id_addr);
s32 sys_mmapper_enable_page_fault_notification(u32 start_addr, u32 q_id);
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, vm::ptr<u32> alloc_addr);
s32 sys_mmapper_unmap_memory(u32 addr, vm::ptr<u32> mem_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)
{
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);

View File

@ -8,55 +8,24 @@
#include "sys_vm.h"
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)",
vsize, psize, cid, flag, policy, addr);
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);
// Check virtual size.
if((vsize < (0x100000 * 32)) || (vsize > (0x100000 * 256)))
{
return CELL_EINVAL;
}
// Check physical size.
if(psize > (0x100000 * 256))
{
return CELL_ENOMEM;
}
LV2_LOCK;
// 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.
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)
// Map memory
if (!Memory.Map(new_addr, vsize))
{
return CELL_ENOMEM;
}
// Write a pointer for the allocated memory.
vm::write32(addr, new_addr);
*addr = new_addr;
return CELL_OK;
}
@ -65,211 +34,99 @@ s32 sys_vm_unmap(u32 addr)
{
sys_vm.Error("sys_vm_unmap(addr=0x%x)", addr);
// Unmap memory.
assert(addr == 0x60000000 || addr == 0x70000000);
if(!Memory.Unmap(addr)) return CELL_EINVAL;
LV2_LOCK;
if (!Memory.Unmap(addr))
{
return CELL_EINVAL;
}
return CELL_OK;
}
s32 sys_vm_append_memory(u32 addr, u32 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;
sys_vm.Todo("sys_vm_append_memory(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_return_memory(u32 addr, u32 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;
sys_vm.Todo("sys_vm_return_memory(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
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;
}
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;
}
s32 sys_vm_touch(u32 addr, u32 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.
sys_vm.Todo("sys_vm_touch(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_flush(u32 addr, u32 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.
sys_vm.Todo("sys_vm_flush(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_invalidate(u32 addr, u32 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.
sys_vm.Todo("sys_vm_invalidate(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_store(u32 addr, u32 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.
sys_vm.Todo("sys_vm_store(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
s32 sys_vm_sync(u32 addr, u32 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.
sys_vm.Todo("sys_vm_sync(addr=0x%x, size=0x%x)", addr, size);
return CELL_OK;
}
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.
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;
*result = SYS_VM_STATE_ON_MEMORY;
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_spu = 0;
stat->page_in = 0;
stat->page_out = 0;
stat->pmem_total = current_ct->size;
stat->pmem_total = 0;
stat->pmem_used = 0;
stat->timestamp = 0;
return CELL_OK;
}
}

View File

@ -4,13 +4,13 @@ namespace vm { using namespace ps3; }
enum : u64
{
SYS_VM_TEST_INVALID = 0,
SYS_VM_TEST_UNUSED = 1,
SYS_VM_TEST_ALLOCATED = 2,
SYS_VM_TEST_STORED = 4,
SYS_VM_STATE_INVALID = 0ull,
SYS_VM_STATE_UNUSED = 1ull,
SYS_VM_STATE_ON_MEMORY = 2ull,
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_spu; // Number of bad virtual memory accesses from a SPU thread.
@ -22,7 +22,7 @@ struct sys_vm_statistics
};
// 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_append_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_sync(u32 addr, u32 size);
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...");
SetMenuBar(menubar);
#ifdef _WIN32
SetIcon(wxICON(frame_icon));
#endif
// Panels
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
#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
#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
{
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
{
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> 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_ALIGN(type, align) static_assert(__alignof(type) == align, "Invalid " #type " type alignment")