mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-09 08:21:29 +12:00
Memory cleanup, page flags implemented
RSXCMDMem, SPRXMem, MmaperMem removed MainMem range fixed
This commit is contained in:
parent
0eebfb0aaa
commit
267de68441
23 changed files with 259 additions and 260 deletions
|
@ -1281,7 +1281,7 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
|
||||||
const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1;
|
const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1;
|
||||||
const u32 target = (addr + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1);
|
const u32 target = (addr + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1);
|
||||||
|
|
||||||
const u32 instr = Memory.IsGoodAddr(target, 4) ? vm::psv::read32(target) : 0;
|
const u32 instr = vm::check_addr(target, 4) ? vm::psv::read32(target) : 0;
|
||||||
|
|
||||||
// possibly a call to imported function:
|
// possibly a call to imported function:
|
||||||
if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090)
|
if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090)
|
||||||
|
|
|
@ -39,7 +39,7 @@ std::array<std::atomic<u32>, TLS_MAX> g_armv7_tls_owners;
|
||||||
|
|
||||||
void armv7_init_tls()
|
void armv7_init_tls()
|
||||||
{
|
{
|
||||||
g_armv7_tls_start = Emu.GetTLSMemsz() ? vm::cast(Memory.PSV.RAM.AllocAlign(Emu.GetTLSMemsz() * TLS_MAX, 4096)) : 0;
|
g_armv7_tls_start = Emu.GetTLSMemsz() ? Memory.PSV.RAM.AllocAlign(Emu.GetTLSMemsz() * TLS_MAX, 4096) : 0;
|
||||||
|
|
||||||
for (auto& v : g_armv7_tls_owners)
|
for (auto& v : g_armv7_tls_owners)
|
||||||
{
|
{
|
||||||
|
@ -126,7 +126,7 @@ void ARMv7Thread::InitStack()
|
||||||
if (!m_stack_addr)
|
if (!m_stack_addr)
|
||||||
{
|
{
|
||||||
assert(m_stack_size);
|
assert(m_stack_size);
|
||||||
m_stack_addr = vm::cast(Memory.Alloc(m_stack_size, 4096));
|
m_stack_addr = Memory.Alloc(m_stack_size, 4096);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ cpu_thread& armv7_thread::args(std::initializer_list<std::string> values)
|
||||||
argc++;
|
argc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
argv = vm::cast(Memory.PSV.RAM.AllocAlign(argv_size, 4096)); // allocate arg list
|
argv = Memory.PSV.RAM.AllocAlign(argv_size, 4096); // allocate arg list
|
||||||
memcpy(vm::get_ptr(argv), argv_data.data(), argv_size); // copy arg list
|
memcpy(vm::get_ptr(argv), argv_data.data(), argv_size); // copy arg list
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
|
|
@ -85,7 +85,7 @@ void PPUThread::InitStack()
|
||||||
if (!m_stack_addr)
|
if (!m_stack_addr)
|
||||||
{
|
{
|
||||||
assert(m_stack_size);
|
assert(m_stack_size);
|
||||||
m_stack_addr = vm::cast(Memory.StackMem.AllocAlign(m_stack_size, 4096));
|
m_stack_addr = Memory.StackMem.AllocAlign(m_stack_size, 4096);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,55 +4,8 @@
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Emu/Cell/RawSPUThread.h"
|
#include "Emu/Cell/RawSPUThread.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
|
|
||||||
#ifndef MAP_ANONYMOUS
|
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#include <Windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MemoryBase Memory;
|
MemoryBase Memory;
|
||||||
|
|
||||||
void MemoryBase::RegisterPages(u32 addr, u32 size)
|
|
||||||
{
|
|
||||||
assert(size && (size | addr) % 4096 == 0);
|
|
||||||
|
|
||||||
LV2_LOCK(0);
|
|
||||||
|
|
||||||
//LOG_NOTICE(MEMORY, "RegisterPages(addr=0x%x, size=0x%x)", addr, size);
|
|
||||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
|
||||||
{
|
|
||||||
if (m_pages[i])
|
|
||||||
{
|
|
||||||
LOG_ERROR(MEMORY, "Page already registered (addr=0x%x)", i * 4096);
|
|
||||||
Emu.Pause();
|
|
||||||
}
|
|
||||||
m_pages[i] = 1; // TODO: define page parameters
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MemoryBase::UnregisterPages(u32 addr, u32 size)
|
|
||||||
{
|
|
||||||
assert(size && (size | addr) % 4096 == 0);
|
|
||||||
|
|
||||||
LV2_LOCK(0);
|
|
||||||
|
|
||||||
//LOG_NOTICE(MEMORY, "UnregisterPages(addr=0x%x, size=0x%x)", addr, size);
|
|
||||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
|
||||||
{
|
|
||||||
if (!m_pages[i])
|
|
||||||
{
|
|
||||||
LOG_ERROR(MEMORY, "Page not registered (addr=0x%x)", i * 4096);
|
|
||||||
Emu.Pause();
|
|
||||||
}
|
|
||||||
m_pages[i] = 0; // TODO: define page parameters
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 MemoryBase::InitRawSPU(MemoryBlock* raw_spu)
|
u32 MemoryBase::InitRawSPU(MemoryBlock* raw_spu)
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
@ -93,7 +46,6 @@ void MemoryBase::Init(MemoryType type)
|
||||||
if (m_inited) return;
|
if (m_inited) return;
|
||||||
m_inited = true;
|
m_inited = true;
|
||||||
|
|
||||||
memset(m_pages, 0, sizeof(m_pages));
|
|
||||||
memset(RawSPUMem, 0, sizeof(RawSPUMem));
|
memset(RawSPUMem, 0, sizeof(RawSPUMem));
|
||||||
|
|
||||||
LOG_NOTICE(MEMORY, "Initializing memory: base_addr = 0x%llx, priv_addr = 0x%llx", (u64)vm::g_base_addr, (u64)vm::g_priv_addr);
|
LOG_NOTICE(MEMORY, "Initializing memory: base_addr = 0x%llx, priv_addr = 0x%llx", (u64)vm::g_base_addr, (u64)vm::g_priv_addr);
|
||||||
|
@ -111,11 +63,8 @@ void MemoryBase::Init(MemoryType type)
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Memory_PS3:
|
case Memory_PS3:
|
||||||
MemoryBlocks.push_back(MainMem.SetRange(0x00010000, 0x2FFF0000));
|
MemoryBlocks.push_back(MainMem.SetRange(0x00010000, 0x1FFF0000));
|
||||||
MemoryBlocks.push_back(UserMemory = PRXMem.SetRange(0x30000000, 0x10000000));
|
MemoryBlocks.push_back(UserMemory = Userspace.SetRange(0x20000000, 0x10000000));
|
||||||
MemoryBlocks.push_back(RSXCMDMem.SetRange(0x40000000, 0x10000000));
|
|
||||||
MemoryBlocks.push_back(SPRXMem.SetRange(0x50000000, 0x10000000));
|
|
||||||
MemoryBlocks.push_back(MmaperMem.SetRange(0xB0000000, 0x10000000));
|
|
||||||
MemoryBlocks.push_back(RSXFBMem.SetRange(0xC0000000, 0x10000000));
|
MemoryBlocks.push_back(RSXFBMem.SetRange(0xC0000000, 0x10000000));
|
||||||
MemoryBlocks.push_back(StackMem.SetRange(0xD0000000, 0x10000000));
|
MemoryBlocks.push_back(StackMem.SetRange(0xD0000000, 0x10000000));
|
||||||
break;
|
break;
|
||||||
|
@ -189,7 +138,7 @@ bool MemoryBase::Map(const u32 addr, const u32 size)
|
||||||
|
|
||||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||||
{
|
{
|
||||||
if (m_pages[i])
|
if (vm::check_addr(i * 4096, 4096))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -220,45 +169,15 @@ bool MemoryBase::Unmap(const u32 addr)
|
||||||
MemBlockInfo::MemBlockInfo(u32 addr, u32 size)
|
MemBlockInfo::MemBlockInfo(u32 addr, u32 size)
|
||||||
: MemInfo(addr, size)
|
: MemInfo(addr, size)
|
||||||
{
|
{
|
||||||
assert(size && (size | addr) % 4096 == 0);
|
vm::page_map(addr, size, vm::page_readable | vm::page_writable | vm::page_executable);
|
||||||
|
|
||||||
void* real_addr = vm::get_ptr(addr);
|
|
||||||
void* priv_addr = vm::get_priv_ptr(addr);
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (!VirtualAlloc(priv_addr, size, MEM_COMMIT, PAGE_READWRITE) || !VirtualAlloc(real_addr, size, MEM_COMMIT, PAGE_READWRITE))
|
|
||||||
#else
|
|
||||||
if (mprotect(real_addr, size, PROT_READ | PROT_WRITE) || mprotect(priv_addr, size, PROT_READ | PROT_WRITE))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
LOG_ERROR(MEMORY, "Memory allocation failed (addr=0x%x, size=0x%x)", addr, size);
|
|
||||||
Emu.Pause();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Memory.RegisterPages(addr, size);
|
|
||||||
|
|
||||||
mem = real_addr;
|
|
||||||
memset(mem, 0, size); // ???
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemBlockInfo::Free()
|
void MemBlockInfo::Free()
|
||||||
{
|
{
|
||||||
if (mem)
|
if (addr && size)
|
||||||
{
|
{
|
||||||
Memory.UnregisterPages(addr, size);
|
vm::page_unmap(addr, size);
|
||||||
#ifdef _WIN32
|
addr = size = 0;
|
||||||
DWORD old;
|
|
||||||
|
|
||||||
if (!VirtualProtect(mem, size, PAGE_NOACCESS, &old) || !VirtualProtect(vm::get_priv_ptr(addr), size, PAGE_NOACCESS, &old))
|
|
||||||
#else
|
|
||||||
if (mprotect(mem, size, PROT_NONE) || mprotect(vm::get_priv_ptr(addr), size, PROT_NONE))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
LOG_ERROR(MEMORY, "Memory deallocation failed (addr=0x%x, size=0x%x)", addr, size);
|
|
||||||
Emu.Pause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,21 +196,14 @@ void MemoryBlock::Init()
|
||||||
{
|
{
|
||||||
range_start = 0;
|
range_start = 0;
|
||||||
range_size = 0;
|
range_size = 0;
|
||||||
|
|
||||||
mem = vm::get_ptr<u8>(0u);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryBlock::InitMemory()
|
void MemoryBlock::InitMemory()
|
||||||
{
|
{
|
||||||
if (!range_size)
|
if (range_size)
|
||||||
{
|
|
||||||
mem = vm::get_ptr<u8>(range_start);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Free();
|
Free();
|
||||||
mem_inf = new MemBlockInfo(range_start, range_size);
|
mem_inf = new MemBlockInfo(range_start, range_size);
|
||||||
mem = (u8*)mem_inf->mem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,16 +30,12 @@ namespace vm
|
||||||
class MemoryBase
|
class MemoryBase
|
||||||
{
|
{
|
||||||
std::vector<MemoryBlock*> MemoryBlocks;
|
std::vector<MemoryBlock*> MemoryBlocks;
|
||||||
u32 m_pages[0x100000000 / 4096]; // information about every page
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MemoryBlock* UserMemory;
|
MemoryBlock* UserMemory;
|
||||||
|
|
||||||
DynamicMemoryBlock MainMem;
|
DynamicMemoryBlock MainMem;
|
||||||
DynamicMemoryBlock SPRXMem;
|
DynamicMemoryBlock Userspace;
|
||||||
DynamicMemoryBlock PRXMem;
|
|
||||||
DynamicMemoryBlock RSXCMDMem;
|
|
||||||
DynamicMemoryBlock MmaperMem;
|
|
||||||
DynamicMemoryBlock RSXFBMem;
|
DynamicMemoryBlock RSXFBMem;
|
||||||
DynamicMemoryBlock StackMem;
|
DynamicMemoryBlock StackMem;
|
||||||
MemoryBlock* RawSPUMem[(0x100000000 - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET];
|
MemoryBlock* RawSPUMem[(0x100000000 - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET];
|
||||||
|
@ -82,27 +78,6 @@ public:
|
||||||
|
|
||||||
void Init(MemoryType type);
|
void Init(MemoryType type);
|
||||||
|
|
||||||
bool IsGoodAddr(const u32 addr)
|
|
||||||
{
|
|
||||||
return m_pages[addr / 4096] != 0; // TODO: define page parameters
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsGoodAddr(const u32 addr, const u32 size)
|
|
||||||
{
|
|
||||||
if (!size || addr + size - 1 < addr)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
|
|
||||||
{
|
|
||||||
if (!m_pages[i]) return false; // TODO: define page parameters
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
__noinline void WriteMMIO32(u32 addr, const u32 data);
|
__noinline void WriteMMIO32(u32 addr, const u32 data);
|
||||||
|
|
|
@ -22,8 +22,6 @@ struct MemInfo
|
||||||
|
|
||||||
struct MemBlockInfo : public MemInfo
|
struct MemBlockInfo : public MemInfo
|
||||||
{
|
{
|
||||||
void *mem;
|
|
||||||
|
|
||||||
MemBlockInfo(u32 addr, u32 size);
|
MemBlockInfo(u32 addr, u32 size);
|
||||||
|
|
||||||
void Free();
|
void Free();
|
||||||
|
@ -32,27 +30,26 @@ struct MemBlockInfo : public MemInfo
|
||||||
|
|
||||||
MemBlockInfo(MemBlockInfo &&other)
|
MemBlockInfo(MemBlockInfo &&other)
|
||||||
: MemInfo(other.addr,other.size)
|
: MemInfo(other.addr,other.size)
|
||||||
, mem(other.mem)
|
|
||||||
{
|
{
|
||||||
other.mem = nullptr;
|
other.addr = 0;
|
||||||
|
other.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemBlockInfo& operator =(MemBlockInfo &other) = delete;
|
MemBlockInfo& operator =(MemBlockInfo &other) = delete;
|
||||||
|
|
||||||
MemBlockInfo& operator =(MemBlockInfo &&other)
|
MemBlockInfo& operator =(MemBlockInfo &&other)
|
||||||
{
|
{
|
||||||
this->Free();
|
Free();
|
||||||
this->addr = other.addr;
|
this->addr = other.addr;
|
||||||
this->size = other.size;
|
this->size = other.size;
|
||||||
this->mem = other.mem;
|
other.addr = 0;
|
||||||
other.mem = nullptr;
|
other.size = 0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~MemBlockInfo()
|
~MemBlockInfo()
|
||||||
{
|
{
|
||||||
Free();
|
Free();
|
||||||
mem = nullptr;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,7 +73,6 @@ struct VirtualMemInfo : public MemInfo
|
||||||
class MemoryBlock
|
class MemoryBlock
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
u8* mem;
|
|
||||||
u32 range_start;
|
u32 range_start;
|
||||||
u32 range_size;
|
u32 range_size;
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,8 @@ namespace vm
|
||||||
|
|
||||||
void* const g_base_addr = (atexit(finalize), initialize());
|
void* const g_base_addr = (atexit(finalize), initialize());
|
||||||
|
|
||||||
|
std::array<atomic_le_t<u8>, 0x100000000ull / 4096> g_page_info = {}; // information about every page
|
||||||
|
|
||||||
class reservation_mutex_t
|
class reservation_mutex_t
|
||||||
{
|
{
|
||||||
std::atomic<NamedThreadBase*> m_owner;
|
std::atomic<NamedThreadBase*> m_owner;
|
||||||
|
@ -211,6 +213,12 @@ namespace vm
|
||||||
{
|
{
|
||||||
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
||||||
|
|
||||||
|
u8 flags = g_page_info[addr >> 12].read_relaxed();
|
||||||
|
if (!(flags & page_writable) || !(flags & page_allocated) || (flags & page_no_reservations))
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::reservation_acquire(addr=0x%x, size=0x%x) failed (invalid page flags: 0x%x)", addr, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
// silent unlocking to prevent priority boost for threads going to break reservation
|
// silent unlocking to prevent priority boost for threads going to break reservation
|
||||||
//g_reservation_mutex.do_notify = false;
|
//g_reservation_mutex.do_notify = false;
|
||||||
|
|
||||||
|
@ -272,13 +280,9 @@ namespace vm
|
||||||
{
|
{
|
||||||
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
||||||
|
|
||||||
|
if (!check_addr(addr))
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
return false;
|
||||||
|
|
||||||
if (!Memory.IsGoodAddr(addr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_writing)
|
if (is_writing)
|
||||||
|
@ -335,11 +339,157 @@ namespace vm
|
||||||
_reservation_break(addr);
|
_reservation_break(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_addr(u32 addr)
|
void page_map(u32 addr, u32 size, u8 flags)
|
||||||
{
|
{
|
||||||
// Checking address before using it is unsafe.
|
assert(size && (size | addr) % 4096 == 0 && flags < page_allocated);
|
||||||
// The only safe way to check it is to protect both actions (checking and using) with mutex that is used for mapping/allocation.
|
|
||||||
return false;
|
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
||||||
|
|
||||||
|
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||||
|
{
|
||||||
|
if (g_page_info[i].read_relaxed())
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::page_map(addr=0x%x, size=0x%x, flags=0x%x) failed (already mapped at 0x%x)", addr, size, flags, i * 4096);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* real_addr = vm::get_ptr(addr);
|
||||||
|
void* priv_addr = vm::get_priv_ptr(addr);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto protection = flags & page_writable ? PAGE_READWRITE : (flags & page_readable ? PAGE_READONLY : PAGE_NOACCESS);
|
||||||
|
if (!VirtualAlloc(priv_addr, size, MEM_COMMIT, PAGE_READWRITE) || !VirtualAlloc(real_addr, size, MEM_COMMIT, protection))
|
||||||
|
#else
|
||||||
|
auto protection = flags & page_writable ? PROT_WRITE | PROT_READ : (flags & page_readable ? PROT_READ : PROT_NONE);
|
||||||
|
if (mprotect(priv_addr, size, PROT_READ | PROT_WRITE) || mprotect(real_addr, size, protection))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::page_map(addr=0x%x, size=0x%x, flags=0x%x) failed (API)", addr, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||||
|
{
|
||||||
|
if (g_page_info[i].exchange(flags | page_allocated))
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::page_map(addr=0x%x, size=0x%x, flags=0x%x) failed (concurrent access at 0x%x)", addr, size, flags, i * 4096);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(priv_addr, 0, size); // ???
|
||||||
|
}
|
||||||
|
|
||||||
|
bool page_protect(u32 addr, u32 size, u8 flags_test, u8 flags_set, u8 flags_clear)
|
||||||
|
{
|
||||||
|
u8 flags_inv = flags_set & flags_clear;
|
||||||
|
|
||||||
|
assert(size && (size | addr) % 4096 == 0);
|
||||||
|
|
||||||
|
flags_test |= page_allocated;
|
||||||
|
|
||||||
|
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
||||||
|
|
||||||
|
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||||
|
{
|
||||||
|
if ((g_page_info[i].read_relaxed() & flags_test) != (flags_test | page_allocated))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!flags_inv && !flags_set && !flags_clear)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||||
|
{
|
||||||
|
_reservation_break(i * 4096);
|
||||||
|
|
||||||
|
const u8 f1 = g_page_info[i]._or(flags_set & ~flags_inv) & (page_writable | page_readable);
|
||||||
|
g_page_info[i]._and_not(flags_clear & ~flags_inv);
|
||||||
|
const u8 f2 = (g_page_info[i] ^= flags_inv) & (page_writable | page_readable);
|
||||||
|
|
||||||
|
if (f1 != f2)
|
||||||
|
{
|
||||||
|
void* real_addr = vm::get_ptr(i * 4096);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD old;
|
||||||
|
|
||||||
|
auto protection = f2 & page_writable ? PAGE_READWRITE : (f2 & page_readable ? PAGE_READONLY : PAGE_NOACCESS);
|
||||||
|
if (!VirtualProtect(real_addr, size, protection, &old))
|
||||||
|
#else
|
||||||
|
auto protection = f2 & page_writable ? PROT_WRITE | PROT_READ : (f2 & page_readable ? PROT_READ : PROT_NONE);
|
||||||
|
if (mprotect(real_addr, size, protection))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::page_protect(addr=0x%x, size=0x%x, flags_test=0x%x, flags_set=0x%x, flags_clear=0x%x) failed (API)", addr, size, flags_test, flags_set, flags_clear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void page_unmap(u32 addr, u32 size)
|
||||||
|
{
|
||||||
|
assert(size && (size | addr) % 4096 == 0);
|
||||||
|
|
||||||
|
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
||||||
|
|
||||||
|
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||||
|
{
|
||||||
|
if (!(g_page_info[i].read_relaxed() & page_allocated))
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::page_unmap(addr=0x%x, size=0x%x) failed (not mapped at 0x%x)", addr, size, i * 4096);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||||
|
{
|
||||||
|
_reservation_break(i * 4096);
|
||||||
|
|
||||||
|
if (!(g_page_info[i].exchange(0) & page_allocated))
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::page_unmap(addr=0x%x, size=0x%x) failed (concurrent access at 0x%x)", addr, size, i * 4096);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* real_addr = vm::get_ptr(addr);
|
||||||
|
void* priv_addr = vm::get_priv_ptr(addr);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD old;
|
||||||
|
|
||||||
|
if (!VirtualProtect(real_addr, size, PAGE_NOACCESS, &old) || !VirtualProtect(priv_addr, size, PAGE_NOACCESS, &old))
|
||||||
|
#else
|
||||||
|
if (mprotect(real_addr, size, PROT_NONE) || mprotect(priv_addr, size, PROT_NONE))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
throw fmt::format("vm::page_unmap(addr=0x%x, size=0x%x) failed (API)", addr, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not checked if address is writable/readable. Checking address before using it is unsafe.
|
||||||
|
// The only safe way to check it is to protect both actions (checking and using) with mutex that is used for mapping/allocation.
|
||||||
|
bool check_addr(u32 addr, u32 size)
|
||||||
|
{
|
||||||
|
assert(size);
|
||||||
|
|
||||||
|
if (addr + (size - 1) < addr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
|
||||||
|
{
|
||||||
|
if ((g_page_info[i].read_sync() & page_allocated) != page_allocated)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
|
@ -406,6 +556,19 @@ namespace vm
|
||||||
Memory.MainMem.Free(addr);
|
Memory.MainMem.Free(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 user_space_alloc(u32 size)
|
||||||
|
{
|
||||||
|
return Memory.Userspace.AllocAlign(size, 1);
|
||||||
|
}
|
||||||
|
u32 user_space_fixed_alloc(u32 addr, u32 size)
|
||||||
|
{
|
||||||
|
return Memory.Userspace.AllocFixed(addr, size) ? addr : 0;
|
||||||
|
}
|
||||||
|
void user_space_dealloc(u32 addr)
|
||||||
|
{
|
||||||
|
Memory.Userspace.Free(addr);
|
||||||
|
}
|
||||||
|
|
||||||
u32 g_stack_offset = 0;
|
u32 g_stack_offset = 0;
|
||||||
|
|
||||||
u32 stack_alloc(u32 size)
|
u32 stack_alloc(u32 size)
|
||||||
|
@ -421,32 +584,6 @@ namespace vm
|
||||||
Memory.StackMem.Free(addr);
|
Memory.StackMem.Free(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sprx_alloc(u32 size)
|
|
||||||
{
|
|
||||||
return Memory.SPRXMem.AllocAlign(size, 1);
|
|
||||||
}
|
|
||||||
u32 sprx_fixed_alloc(u32 addr, u32 size)
|
|
||||||
{
|
|
||||||
return Memory.SPRXMem.AllocFixed(Memory.SPRXMem.GetStartAddr() + addr, size) ? Memory.SPRXMem.GetStartAddr() + addr : 0;
|
|
||||||
}
|
|
||||||
void sprx_dealloc(u32 addr)
|
|
||||||
{
|
|
||||||
Memory.SPRXMem.Free(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 user_space_alloc(u32 size)
|
|
||||||
{
|
|
||||||
return Memory.PRXMem.AllocAlign(size, 1);
|
|
||||||
}
|
|
||||||
u32 user_space_fixed_alloc(u32 addr, u32 size)
|
|
||||||
{
|
|
||||||
return Memory.PRXMem.AllocFixed(addr, size) ? addr : 0;
|
|
||||||
}
|
|
||||||
void user_space_dealloc(u32 addr)
|
|
||||||
{
|
|
||||||
Memory.PRXMem.Free(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
Memory.Init(Memory_PS3);
|
Memory.Init(Memory_PS3);
|
||||||
|
@ -471,13 +608,9 @@ namespace vm
|
||||||
|
|
||||||
location_info g_locations[memory_location_count] =
|
location_info g_locations[memory_location_count] =
|
||||||
{
|
{
|
||||||
{ 0x00010000, 0x2FFF0000, ps3::main_alloc, ps3::main_fixed_alloc, ps3::main_dealloc },
|
{ 0x00010000, 0x1FFF0000, ps3::main_alloc, ps3::main_fixed_alloc, ps3::main_dealloc },
|
||||||
|
{ 0x20000000, 0x10000000, ps3::user_space_alloc, ps3::user_space_fixed_alloc, ps3::user_space_dealloc },
|
||||||
{ 0xD0000000, 0x10000000, ps3::stack_alloc, ps3::stack_fixed_alloc, ps3::stack_dealloc },
|
{ 0xD0000000, 0x10000000, ps3::stack_alloc, ps3::stack_fixed_alloc, ps3::stack_dealloc },
|
||||||
|
|
||||||
//remove me
|
|
||||||
{ 0x00010000, 0x2FFF0000, ps3::sprx_alloc, ps3::sprx_fixed_alloc, ps3::sprx_dealloc },
|
|
||||||
|
|
||||||
{ 0x30000000, 0x10000000, ps3::user_space_alloc, ps3::user_space_fixed_alloc, ps3::user_space_dealloc },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void close()
|
void close()
|
||||||
|
|
|
@ -8,16 +8,24 @@ namespace vm
|
||||||
enum memory_location : uint
|
enum memory_location : uint
|
||||||
{
|
{
|
||||||
main,
|
main,
|
||||||
|
user_space,
|
||||||
stack,
|
stack,
|
||||||
|
|
||||||
//remove me
|
|
||||||
sprx,
|
|
||||||
|
|
||||||
user_space,
|
|
||||||
|
|
||||||
memory_location_count
|
memory_location_count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum page_info_t : u8
|
||||||
|
{
|
||||||
|
page_readable = (1 << 0),
|
||||||
|
page_writable = (1 << 1),
|
||||||
|
page_executable = (1 << 2),
|
||||||
|
|
||||||
|
page_fault_notification = (1 << 3),
|
||||||
|
page_no_reservations = (1 << 4),
|
||||||
|
|
||||||
|
page_allocated = (1 << 7),
|
||||||
|
};
|
||||||
|
|
||||||
static void set_stack_size(u32 size) {}
|
static void set_stack_size(u32 size) {}
|
||||||
static void initialize_stack() {}
|
static void initialize_stack() {}
|
||||||
|
|
||||||
|
@ -34,11 +42,23 @@ namespace vm
|
||||||
bool reservation_acquire(void* data, u32 addr, u32 size, const std::function<void()>& callback = nullptr);
|
bool reservation_acquire(void* data, u32 addr, u32 size, const std::function<void()>& callback = nullptr);
|
||||||
// attempt to atomically update reserved memory
|
// attempt to atomically update reserved memory
|
||||||
bool reservation_update(u32 addr, const void* data, u32 size);
|
bool reservation_update(u32 addr, const void* data, u32 size);
|
||||||
|
// for internal use
|
||||||
bool reservation_query(u32 addr, bool is_writing);
|
bool reservation_query(u32 addr, bool is_writing);
|
||||||
|
// for internal use
|
||||||
void reservation_free();
|
void reservation_free();
|
||||||
// perform complete operation
|
// perform complete operation
|
||||||
void reservation_op(u32 addr, u32 size, std::function<void()> proc);
|
void reservation_op(u32 addr, u32 size, std::function<void()> proc);
|
||||||
|
|
||||||
|
// for internal use
|
||||||
|
void page_map(u32 addr, u32 size, u8 flags);
|
||||||
|
// for internal use
|
||||||
|
bool page_protect(u32 addr, u32 size, u8 flags_test = 0, u8 flags_set = 0, u8 flags_clear = 0);
|
||||||
|
// for internal use
|
||||||
|
void page_unmap(u32 addr, u32 size);
|
||||||
|
|
||||||
|
// unsafe address check
|
||||||
|
bool check_addr(u32 addr, u32 size = 1);
|
||||||
|
|
||||||
bool map(u32 addr, u32 size, u32 flags);
|
bool map(u32 addr, u32 size, u32 flags);
|
||||||
bool unmap(u32 addr, u32 size = 0, u32 flags = 0);
|
bool unmap(u32 addr, u32 size = 0, u32 flags = 0);
|
||||||
u32 alloc(u32 size, memory_location location = user_space);
|
u32 alloc(u32 size, memory_location location = user_space);
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace vm
|
||||||
|
|
||||||
void alloc()
|
void alloc()
|
||||||
{
|
{
|
||||||
m_addr = vm::cast(Memory.Alloc(size(), m_align));
|
m_addr = Memory.Alloc(size(), m_align);
|
||||||
m_ptr = vm::get_ptr<T>(m_addr);
|
m_ptr = vm::get_ptr<T>(m_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ namespace vm
|
||||||
|
|
||||||
void alloc()
|
void alloc()
|
||||||
{
|
{
|
||||||
m_addr = vm::cast(Memory.Alloc(size(), m_align));
|
m_addr = Memory.Alloc(size(), m_align);
|
||||||
m_ptr = vm::get_ptr<T>(m_addr);
|
m_ptr = vm::get_ptr<T>(m_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,7 @@ struct gcmInfo
|
||||||
u32 config_addr;
|
u32 config_addr;
|
||||||
u32 context_addr;
|
u32 context_addr;
|
||||||
u32 control_addr;
|
u32 control_addr;
|
||||||
|
u32 label_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CellGcmSurface
|
struct CellGcmSurface
|
||||||
|
|
|
@ -104,12 +104,7 @@ void GLTexture::Init(RSXTexture& tex)
|
||||||
|
|
||||||
Bind();
|
Bind();
|
||||||
|
|
||||||
const u64 texaddr = GetAddress(tex.GetOffset(), tex.GetLocation());
|
const u32 texaddr = GetAddress(tex.GetOffset(), tex.GetLocation());
|
||||||
if (!Memory.IsGoodAddr(texaddr))
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Bad texture address=0x%x", texaddr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//LOG_WARNING(RSX, "texture addr = 0x%x, width = %d, height = %d, max_aniso=%d, mipmap=%d, remap=0x%x, zfunc=0x%x, wraps=0x%x, wrapt=0x%x, wrapr=0x%x, minlod=0x%x, maxlod=0x%x",
|
//LOG_WARNING(RSX, "texture addr = 0x%x, width = %d, height = %d, max_aniso=%d, mipmap=%d, remap=0x%x, zfunc=0x%x, wraps=0x%x, wrapt=0x%x, wrapr=0x%x, minlod=0x%x, maxlod=0x%x",
|
||||||
// m_offset, m_width, m_height, m_maxaniso, m_mipmap, m_remap, m_zfunc, m_wraps, m_wrapt, m_wrapr, m_minlod, m_maxlod);
|
// m_offset, m_width, m_height, m_maxaniso, m_mipmap, m_remap, m_zfunc, m_wraps, m_wrapt, m_wrapr, m_minlod, m_maxlod);
|
||||||
|
|
||||||
|
@ -1242,11 +1237,6 @@ void GLGSRender::WriteDepthBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 address = GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000);
|
u32 address = GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000);
|
||||||
if (!Memory.IsGoodAddr(address))
|
|
||||||
{
|
|
||||||
LOG_WARNING(RSX, "Bad depth buffer address: address=0x%x, offset=0x%x, dma=0x%x", address, m_surface_offset_z, m_context_dma_z);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ptr = vm::get_ptr<void>(address);
|
auto ptr = vm::get_ptr<void>(address);
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, g_pbo[4]);
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, g_pbo[4]);
|
||||||
|
@ -1279,11 +1269,6 @@ void GLGSRender::WriteColorBufferA()
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 address = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000);
|
u32 address = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000);
|
||||||
if (!Memory.IsGoodAddr(address))
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Bad color buffer A address: address=0x%x, offset=0x%x, dma=0x%x", address, m_surface_offset_a, m_context_dma_color_a);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
checkForGlError("WriteColorBufferA(): glReadBuffer");
|
checkForGlError("WriteColorBufferA(): glReadBuffer");
|
||||||
|
@ -1310,11 +1295,6 @@ void GLGSRender::WriteColorBufferB()
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 address = GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000);
|
u32 address = GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000);
|
||||||
if (!Memory.IsGoodAddr(address))
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Bad color buffer B address: address=0x%x, offset=0x%x, dma=0x%x", address, m_surface_offset_b, m_context_dma_color_b);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT1);
|
glReadBuffer(GL_COLOR_ATTACHMENT1);
|
||||||
checkForGlError("WriteColorBufferB(): glReadBuffer");
|
checkForGlError("WriteColorBufferB(): glReadBuffer");
|
||||||
|
@ -1341,11 +1321,6 @@ void GLGSRender::WriteColorBufferC()
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 address = GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000);
|
u32 address = GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000);
|
||||||
if (!Memory.IsGoodAddr(address))
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Bad color buffer C address: address=0x%x, offset=0x%x, dma=0x%x", address, m_surface_offset_c, m_context_dma_color_c);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT2);
|
glReadBuffer(GL_COLOR_ATTACHMENT2);
|
||||||
checkForGlError("WriteColorBufferC(): glReadBuffer");
|
checkForGlError("WriteColorBufferC(): glReadBuffer");
|
||||||
|
@ -1372,11 +1347,6 @@ void GLGSRender::WriteColorBufferD()
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 address = GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000);
|
u32 address = GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000);
|
||||||
if (!Memory.IsGoodAddr(address))
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Bad color buffer D address: address=0x%x, offset=0x%x, dma=0x%x", address, m_surface_offset_d, m_context_dma_color_d);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT3);
|
glReadBuffer(GL_COLOR_ATTACHMENT3);
|
||||||
checkForGlError("WriteColorBufferD(): glReadBuffer");
|
checkForGlError("WriteColorBufferD(): glReadBuffer");
|
||||||
|
@ -1682,14 +1652,9 @@ void GLGSRender::InitDrawBuffers()
|
||||||
u32 format = GL_BGRA;
|
u32 format = GL_BGRA;
|
||||||
CellGcmDisplayInfo* buffers = vm::get_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
|
CellGcmDisplayInfo* buffers = vm::get_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
|
||||||
u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||||
|
u32 width = buffers[m_gcm_current_buffer].width;
|
||||||
if (Memory.IsGoodAddr(addr))
|
u32 height = buffers[m_gcm_current_buffer].height;
|
||||||
{
|
glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, vm::get_ptr(addr));
|
||||||
u32 width = buffers[m_gcm_current_buffer].width;
|
|
||||||
u32 height = buffers[m_gcm_current_buffer].height;
|
|
||||||
|
|
||||||
glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, vm::get_ptr(addr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2139,17 +2104,9 @@ void GLGSRender::Flip()
|
||||||
format = GL_BGRA;
|
format = GL_BGRA;
|
||||||
CellGcmDisplayInfo* buffers = vm::get_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
|
CellGcmDisplayInfo* buffers = vm::get_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
|
||||||
u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||||
|
width = buffers[m_gcm_current_buffer].width;
|
||||||
if (Memory.IsGoodAddr(addr))
|
height = buffers[m_gcm_current_buffer].height;
|
||||||
{
|
src_buffer = vm::get_ptr<u8>(addr);
|
||||||
width = buffers[m_gcm_current_buffer].width;
|
|
||||||
height = buffers[m_gcm_current_buffer].height;
|
|
||||||
src_buffer = vm::get_ptr<u8>(addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
src_buffer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (m_fbo.IsCreated())
|
else if (m_fbo.IsCreated())
|
||||||
{
|
{
|
||||||
|
|
|
@ -261,7 +261,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
|
||||||
if (m_set_semaphore_offset)
|
if (m_set_semaphore_offset)
|
||||||
{
|
{
|
||||||
m_set_semaphore_offset = false;
|
m_set_semaphore_offset = false;
|
||||||
vm::write32(Memory.RSXCMDMem.GetStartAddr() + m_semaphore_offset, ARGS(0));
|
vm::write32(m_label_addr + m_semaphore_offset, ARGS(0));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
|
||||||
u32 value = ARGS(0);
|
u32 value = ARGS(0);
|
||||||
value = (value & 0xff00ff00) | ((value & 0xff) << 16) | ((value >> 16) & 0xff);
|
value = (value & 0xff00ff00) | ((value & 0xff) << 16) | ((value >> 16) & 0xff);
|
||||||
|
|
||||||
vm::write32(Memory.RSXCMDMem.GetStartAddr() + m_semaphore_offset, value);
|
vm::write32(m_label_addr + m_semaphore_offset, value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,7 @@ public:
|
||||||
u32 m_gcm_current_buffer;
|
u32 m_gcm_current_buffer;
|
||||||
u32 m_ctxt_addr;
|
u32 m_ctxt_addr;
|
||||||
u32 m_report_main_addr;
|
u32 m_report_main_addr;
|
||||||
|
u32 m_label_addr;
|
||||||
|
|
||||||
// DMA
|
// DMA
|
||||||
u32 dma_report;
|
u32 dma_report;
|
||||||
|
|
|
@ -41,8 +41,8 @@ s32 cellAudioInit()
|
||||||
g_audio.start_time = get_system_time();
|
g_audio.start_time = get_system_time();
|
||||||
|
|
||||||
// alloc memory (only once until the emulator is stopped)
|
// alloc memory (only once until the emulator is stopped)
|
||||||
g_audio.buffer = g_audio.buffer ? g_audio.buffer : vm::cast(Memory.MainMem.AllocAlign(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, 4096));
|
g_audio.buffer = g_audio.buffer ? g_audio.buffer : Memory.MainMem.AllocAlign(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, 4096);
|
||||||
g_audio.indexes = g_audio.indexes ? g_audio.indexes : vm::cast(Memory.MainMem.AllocAlign(sizeof(u64) * AUDIO_PORT_COUNT, __alignof(u64)));
|
g_audio.indexes = g_audio.indexes ? g_audio.indexes : Memory.MainMem.AllocAlign(sizeof(u64) * AUDIO_PORT_COUNT, __alignof(u64));
|
||||||
|
|
||||||
// clear memory
|
// clear memory
|
||||||
memset(vm::get_ptr<void>(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT);
|
memset(vm::get_ptr<void>(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT);
|
||||||
|
|
|
@ -76,7 +76,7 @@ void InitOffsetTable()
|
||||||
u32 cellGcmGetLabelAddress(u8 index)
|
u32 cellGcmGetLabelAddress(u8 index)
|
||||||
{
|
{
|
||||||
cellGcmSys->Log("cellGcmGetLabelAddress(index=%d)", index);
|
cellGcmSys->Log("cellGcmGetLabelAddress(index=%d)", index);
|
||||||
return (u32)Memory.RSXCMDMem.GetStartAddr() + 0x10 * index;
|
return gcm_info.label_addr + 0x10 * index;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 location)
|
vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 location)
|
||||||
|
@ -360,8 +360,6 @@ s32 _cellGcmInitBody(vm::ptr<CellGcmContextData> context, u32 cmdSize, u32 ioSiz
|
||||||
current_config.memoryFrequency = 650000000;
|
current_config.memoryFrequency = 650000000;
|
||||||
current_config.coreFrequency = 500000000;
|
current_config.coreFrequency = 500000000;
|
||||||
|
|
||||||
Memory.RSXCMDMem.AllocAlign(cmdSize);
|
|
||||||
|
|
||||||
u32 ctx_begin = ioAddress/* + 0x1000*/;
|
u32 ctx_begin = ioAddress/* + 0x1000*/;
|
||||||
u32 ctx_size = 0x6ffc;
|
u32 ctx_size = 0x6ffc;
|
||||||
current_context.begin = ctx_begin;
|
current_context.begin = ctx_begin;
|
||||||
|
@ -369,9 +367,11 @@ s32 _cellGcmInitBody(vm::ptr<CellGcmContextData> context, u32 cmdSize, u32 ioSiz
|
||||||
current_context.current = current_context.begin;
|
current_context.current = current_context.begin;
|
||||||
current_context.callback.set(be_t<u32>::make(Emu.GetRSXCallback() - 4));
|
current_context.callback.set(be_t<u32>::make(Emu.GetRSXCallback() - 4));
|
||||||
|
|
||||||
gcm_info.context_addr = (u32)Memory.MainMem.AllocAlign(0x1000);
|
gcm_info.context_addr = Memory.MainMem.AllocAlign(0x1000);
|
||||||
gcm_info.control_addr = gcm_info.context_addr + 0x40;
|
gcm_info.control_addr = gcm_info.context_addr + 0x40;
|
||||||
|
|
||||||
|
gcm_info.label_addr = Memory.MainMem.AllocAlign(0x1000); // ???
|
||||||
|
|
||||||
vm::get_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
|
vm::get_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
|
||||||
vm::write32(context.addr(), gcm_info.context_addr);
|
vm::write32(context.addr(), gcm_info.context_addr);
|
||||||
|
|
||||||
|
@ -388,6 +388,7 @@ s32 _cellGcmInitBody(vm::ptr<CellGcmContextData> context, u32 cmdSize, u32 ioSiz
|
||||||
render.m_gcm_buffers_count = 0;
|
render.m_gcm_buffers_count = 0;
|
||||||
render.m_gcm_current_buffer = 0;
|
render.m_gcm_current_buffer = 0;
|
||||||
render.m_main_mem_addr = 0;
|
render.m_main_mem_addr = 0;
|
||||||
|
render.m_label_addr = gcm_info.label_addr;
|
||||||
render.Init(ctx_begin, ctx_size, gcm_info.control_addr, local_addr);
|
render.Init(ctx_begin, ctx_size, gcm_info.control_addr, local_addr);
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
@ -1109,7 +1110,7 @@ int cellGcmSetFlipCommandWithWaitLabel(vm::ptr<CellGcmContextData> ctx, u32 id,
|
||||||
ctx.addr(), id, label_index, label_value);
|
ctx.addr(), id, label_index, label_value);
|
||||||
|
|
||||||
int res = cellGcmSetPrepareFlip(ctx, id);
|
int res = cellGcmSetPrepareFlip(ctx, id);
|
||||||
vm::write32(Memory.RSXCMDMem.GetStartAddr() + 0x10 * label_index, label_value);
|
vm::write32(gcm_info.label_addr + 0x10 * label_index, label_value);
|
||||||
return res < 0 ? CELL_GCM_ERROR_FAILURE : CELL_OK;
|
return res < 0 ? CELL_GCM_ERROR_FAILURE : CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ u32 ppu_get_tls(u32 thread)
|
||||||
if (!g_tls_start)
|
if (!g_tls_start)
|
||||||
{
|
{
|
||||||
g_tls_size = Emu.GetTLSMemsz() + TLS_SYS;
|
g_tls_size = Emu.GetTLSMemsz() + TLS_SYS;
|
||||||
g_tls_start = vm::cast(Memory.MainMem.AllocAlign(g_tls_size * TLS_MAX, 4096)); // memory for up to TLS_MAX threads
|
g_tls_start = Memory.MainMem.AllocAlign(g_tls_size * TLS_MAX, 4096); // memory for up to TLS_MAX threads
|
||||||
sysPrxForUser->Notice("Thread Local Storage initialized (g_tls_start=0x%x, user_size=0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x",
|
sysPrxForUser->Notice("Thread Local Storage initialized (g_tls_start=0x%x, user_size=0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x",
|
||||||
g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz());
|
g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz());
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ SPUThread* spu_thread_initialize(std::shared_ptr<SpuGroupInfo>& group, u32 spu_n
|
||||||
const u32 spu_ep = img.entry_point;
|
const u32 spu_ep = img.entry_point;
|
||||||
// Copy SPU image:
|
// Copy SPU image:
|
||||||
// TODO: use segment info
|
// TODO: use segment info
|
||||||
const u32 spu_offset = vm::cast(Memory.MainMem.AllocAlign(256 * 1024, 4096));
|
const u32 spu_offset = Memory.MainMem.AllocAlign(256 * 1024, 4096);
|
||||||
memcpy(vm::get_ptr<void>(spu_offset), vm::get_ptr<void>(img.addr), 256 * 1024);
|
memcpy(vm::get_ptr<void>(spu_offset), vm::get_ptr<void>(img.addr), 256 * 1024);
|
||||||
|
|
||||||
SPUThread& new_thread = static_cast<SPUThread&>(Emu.GetCPU().AddThread(CPU_THREAD_SPU));
|
SPUThread& new_thread = static_cast<SPUThread&>(Emu.GetCPU().AddThread(CPU_THREAD_SPU));
|
||||||
|
|
|
@ -27,7 +27,7 @@ s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, u32 a
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 = Memory.IsGoodAddr(0x60000000) ? 0x70000000 : 0x60000000;
|
u32 new_addr = vm::check_addr(0x60000000) ? 0x70000000 : 0x60000000;
|
||||||
|
|
||||||
// If container ID is SYS_MEMORY_CONTAINER_ID_INVALID, allocate directly.
|
// If container ID is SYS_MEMORY_CONTAINER_ID_INVALID, allocate directly.
|
||||||
if(cid == SYS_MEMORY_CONTAINER_ID_INVALID)
|
if(cid == SYS_MEMORY_CONTAINER_ID_INVALID)
|
||||||
|
@ -45,7 +45,10 @@ s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, u32 a
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate actual memory using virtual size (physical size is ignored)
|
// Allocate actual memory using virtual size (physical size is ignored)
|
||||||
assert(Memory.Map(new_addr, vsize));
|
if (!Memory.Map(new_addr, vsize))
|
||||||
|
{
|
||||||
|
return CELL_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
// Write a pointer for the allocated memory.
|
// Write a pointer for the allocated memory.
|
||||||
vm::write32(addr, new_addr);
|
vm::write32(addr, new_addr);
|
||||||
|
|
|
@ -251,7 +251,7 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
|
||||||
disasm->offset = vm::get_ptr<u8>(CPU->GetOffset());
|
disasm->offset = vm::get_ptr<u8>(CPU->GetOffset());
|
||||||
for(uint i=0, count = 4; i<m_item_count; ++i, PC += count)
|
for(uint i=0, count = 4; i<m_item_count; ++i, PC += count)
|
||||||
{
|
{
|
||||||
if(!Memory.IsGoodAddr(CPU->GetOffset() + PC, 4))
|
if(!vm::check_addr(CPU->GetOffset() + PC, 4))
|
||||||
{
|
{
|
||||||
m_list->SetItem(i, 0, wxString(IsBreakPoint(PC) ? ">>> " : " ") + wxString::Format("[%08llx] illegal address", PC));
|
m_list->SetItem(i, 0, wxString(IsBreakPoint(PC) ? ">>> " : " ") + wxString::Format("[%08llx] illegal address", PC));
|
||||||
count = 4;
|
count = 4;
|
||||||
|
|
|
@ -45,7 +45,7 @@ void MemoryStringSearcher::Search(wxCommandEvent& event)
|
||||||
u32 strIndex = 0;
|
u32 strIndex = 0;
|
||||||
u32 numFound = 0;
|
u32 numFound = 0;
|
||||||
for (u32 addr = Memory.MainMem.GetStartAddr(); addr < Memory.MainMem.GetEndAddr(); addr++) {
|
for (u32 addr = Memory.MainMem.GetStartAddr(); addr < Memory.MainMem.GetEndAddr(); addr++) {
|
||||||
if (!Memory.IsGoodAddr(addr)) {
|
if (!vm::check_addr(addr)) {
|
||||||
strIndex = 0;
|
strIndex = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,7 +200,7 @@ void MemoryViewerPanel::ShowMemory()
|
||||||
{
|
{
|
||||||
u32 addr = m_addr + row * m_colcount + col;
|
u32 addr = m_addr + row * m_colcount + col;
|
||||||
|
|
||||||
if (Memory.IsGoodAddr(addr))
|
if (vm::check_addr(addr))
|
||||||
{
|
{
|
||||||
const u8 rmem = vm::read8(addr);
|
const u8 rmem = vm::read8(addr);
|
||||||
t_mem_hex_str += wxString::Format("%02x ", rmem);
|
t_mem_hex_str += wxString::Format("%02x ", rmem);
|
||||||
|
|
|
@ -259,14 +259,14 @@ void RSXDebugger::OnChangeToolsAddr(wxCommandEvent& event)
|
||||||
|
|
||||||
void RSXDebugger::OnScrollMemory(wxMouseEvent& event)
|
void RSXDebugger::OnScrollMemory(wxMouseEvent& event)
|
||||||
{
|
{
|
||||||
if(Memory.IsGoodAddr(m_addr))
|
if(vm::check_addr(m_addr))
|
||||||
{
|
{
|
||||||
int items = event.ControlDown() ? m_item_count : 1;
|
int items = event.ControlDown() ? m_item_count : 1;
|
||||||
|
|
||||||
for(int i=0; i<items; ++i)
|
for(int i=0; i<items; ++i)
|
||||||
{
|
{
|
||||||
u32 offset;
|
u32 offset;
|
||||||
if(Memory.IsGoodAddr(m_addr))
|
if(vm::check_addr(m_addr))
|
||||||
{
|
{
|
||||||
u32 cmd = vm::read32(m_addr);
|
u32 cmd = vm::read32(m_addr);
|
||||||
u32 count = (cmd & (CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_CALL))
|
u32 count = (cmd & (CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_CALL))
|
||||||
|
@ -304,7 +304,7 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
|
||||||
#define SHOW_BUFFER(id) \
|
#define SHOW_BUFFER(id) \
|
||||||
{ \
|
{ \
|
||||||
u32 addr = render.m_local_mem_addr + buffers[id].offset; \
|
u32 addr = render.m_local_mem_addr + buffers[id].offset; \
|
||||||
if (Memory.IsGoodAddr(addr) && buffers[id].width && buffers[id].height) \
|
if (vm::check_addr(addr) && buffers[id].width && buffers[id].height) \
|
||||||
MemoryViewerPanel::ShowImage(this, addr, 3, buffers[id].width, buffers[id].height, true); \
|
MemoryViewerPanel::ShowImage(this, addr, 3, buffers[id].width, buffers[id].height, true); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
|
@ -316,7 +316,7 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
|
||||||
if (event.GetId() == p_buffer_tex->GetId())
|
if (event.GetId() == p_buffer_tex->GetId())
|
||||||
{
|
{
|
||||||
u8 location = render.m_textures[m_cur_texture].GetLocation();
|
u8 location = render.m_textures[m_cur_texture].GetLocation();
|
||||||
if(location <= 1 && Memory.IsGoodAddr(GetAddress(render.m_textures[m_cur_texture].GetOffset(), location))
|
if(location <= 1 && vm::check_addr(GetAddress(render.m_textures[m_cur_texture].GetOffset(), location))
|
||||||
&& render.m_textures[m_cur_texture].GetWidth() && render.m_textures[m_cur_texture].GetHeight())
|
&& render.m_textures[m_cur_texture].GetWidth() && render.m_textures[m_cur_texture].GetHeight())
|
||||||
MemoryViewerPanel::ShowImage(this,
|
MemoryViewerPanel::ShowImage(this,
|
||||||
GetAddress(render.m_textures[m_cur_texture].GetOffset(), location), 1,
|
GetAddress(render.m_textures[m_cur_texture].GetOffset(), location), 1,
|
||||||
|
@ -380,7 +380,7 @@ void RSXDebugger::GetMemory()
|
||||||
{
|
{
|
||||||
m_list_commands->SetItem(i, 0, wxString::Format("%08x", addr));
|
m_list_commands->SetItem(i, 0, wxString::Format("%08x", addr));
|
||||||
|
|
||||||
if (isReady && Memory.IsGoodAddr(addr))
|
if (isReady && vm::check_addr(addr))
|
||||||
{
|
{
|
||||||
u32 cmd = vm::read32(addr);
|
u32 cmd = vm::read32(addr);
|
||||||
u32 count = (cmd >> 18) & 0x7ff;
|
u32 count = (cmd >> 18) & 0x7ff;
|
||||||
|
@ -409,13 +409,13 @@ void RSXDebugger::GetBuffers()
|
||||||
// TODO: Currently it only supports color buffers
|
// TODO: Currently it only supports color buffers
|
||||||
for (u32 bufferId=0; bufferId < render.m_gcm_buffers_count; bufferId++)
|
for (u32 bufferId=0; bufferId < render.m_gcm_buffers_count; bufferId++)
|
||||||
{
|
{
|
||||||
if(!Memory.IsGoodAddr(render.m_gcm_buffers_addr))
|
if(!vm::check_addr(render.m_gcm_buffers_addr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto buffers = vm::get_ptr<CellGcmDisplayInfo>(render.m_gcm_buffers_addr);
|
auto buffers = vm::get_ptr<CellGcmDisplayInfo>(render.m_gcm_buffers_addr);
|
||||||
u32 RSXbuffer_addr = render.m_local_mem_addr + buffers[bufferId].offset;
|
u32 RSXbuffer_addr = render.m_local_mem_addr + buffers[bufferId].offset;
|
||||||
|
|
||||||
if(!Memory.IsGoodAddr(RSXbuffer_addr))
|
if(!vm::check_addr(RSXbuffer_addr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto RSXbuffer = vm::get_ptr<unsigned char>(RSXbuffer_addr);
|
auto RSXbuffer = vm::get_ptr<unsigned char>(RSXbuffer_addr);
|
||||||
|
@ -467,7 +467,7 @@ void RSXDebugger::GetBuffers()
|
||||||
|
|
||||||
u32 TexBuffer_addr = GetAddress(offset, location);
|
u32 TexBuffer_addr = GetAddress(offset, location);
|
||||||
|
|
||||||
if(!Memory.IsGoodAddr(TexBuffer_addr))
|
if(!vm::check_addr(TexBuffer_addr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned char* TexBuffer = vm::get_ptr<unsigned char>(TexBuffer_addr);
|
unsigned char* TexBuffer = vm::get_ptr<unsigned char>(TexBuffer_addr);
|
||||||
|
|
|
@ -101,7 +101,7 @@ namespace loader
|
||||||
segment.size = phdr.p_memsz;
|
segment.size = phdr.p_memsz;
|
||||||
segment.size_file = phdr.p_filesz;
|
segment.size_file = phdr.p_filesz;
|
||||||
|
|
||||||
segment.begin.set(vm::alloc(segment.size, vm::sprx));
|
segment.begin.set(vm::alloc(segment.size, vm::main));
|
||||||
|
|
||||||
if (!segment.begin)
|
if (!segment.begin)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue