mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
Memory (unfinished)
This commit is contained in:
parent
1189503b4d
commit
e6c628caba
@ -530,10 +530,12 @@ bool get_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, size_
|
||||
else if (reg - X64R_AL < 4 && d_size == 1)
|
||||
{
|
||||
out_value = (u8)(*X64REG(context, reg - X64R_AL));
|
||||
return true;
|
||||
}
|
||||
else if (reg - X64R_AH < 4 && d_size == 1)
|
||||
{
|
||||
out_value = (u8)(*X64REG(context, reg - X64R_AH) >> 8);
|
||||
return true;
|
||||
}
|
||||
else if (reg == X64_IMM32)
|
||||
{
|
||||
@ -549,6 +551,7 @@ bool get_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, size_
|
||||
else if (reg == X64R_ECX)
|
||||
{
|
||||
out_value = (u32)RCX(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERROR(GENERAL, "get_x64_reg_value(): invalid arguments (reg=%d, d_size=%lld, i_size=%lld)", reg, d_size, i_size);
|
||||
@ -571,7 +574,7 @@ bool put_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, u64 v
|
||||
|
||||
void fix_x64_reg_op(x64_context* context, x64_op_t& op, x64_reg_t& reg, size_t& d_size, size_t& i_size)
|
||||
{
|
||||
if (op == X64OP_MOVS && reg != X64_NOT_SET)
|
||||
if (op == X64OP_MOVS && reg != X64_NOT_SET) // get "full" access size from RCX register
|
||||
{
|
||||
u64 counter;
|
||||
if (!get_x64_reg_value(context, reg, 8, i_size, counter))
|
||||
@ -584,6 +587,8 @@ void fix_x64_reg_op(x64_context* context, x64_op_t& op, x64_reg_t& reg, size_t&
|
||||
}
|
||||
|
||||
d_size *= counter;
|
||||
reg = X64_NOT_SET;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -600,6 +605,29 @@ bool handle_access_violation(const u32 addr, bool is_writing, x64_context* conte
|
||||
decode_x64_reg_op(code, op, reg, d_size, i_size);
|
||||
fix_x64_reg_op(context, op, reg, d_size, i_size);
|
||||
|
||||
if (d_size + addr >= 0x100000000ull)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "Invalid d_size (0x%llx)", d_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (op == X64OP_CMPXCHG)
|
||||
{
|
||||
// detect whether this instruction can't actually modify memory to avoid breaking reservation;
|
||||
// this may theoretically cause endless loop, but it shouldn't be a problem if only read_sync() generates such instruction
|
||||
u64 cmp, exch;
|
||||
if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cmp == exch)
|
||||
{
|
||||
// could also be emulated without attempt to write memory
|
||||
is_writing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// check if address is RawSPU MMIO register
|
||||
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
@ -645,7 +673,7 @@ bool handle_access_violation(const u32 addr, bool is_writing, x64_context* conte
|
||||
}
|
||||
|
||||
// check if fault is caused by reservation
|
||||
if (vm::reservation_query(addr, is_writing))
|
||||
if (vm::reservation_query(addr, (u32)d_size, is_writing))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -203,7 +203,10 @@ void SPUThread::WriteSNR(bool number, u32 value)
|
||||
|
||||
void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
|
||||
{
|
||||
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
|
||||
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK))
|
||||
{
|
||||
_mm_mfence();
|
||||
}
|
||||
|
||||
u32 eal = vm::cast(ea, "ea");
|
||||
|
||||
@ -298,7 +301,7 @@ void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFC
|
||||
|
||||
if (Ini.HLELogging.GetValue() || rec->s.data())
|
||||
{
|
||||
LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)", i, list_size, rec->s, rec->ts, rec->ea, lsa | (addr & 0xf));
|
||||
LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s=0x%x, ts=0x%x, eal=0x%x (lsa=0x%x)", i, list_size, rec->s, rec->ts, rec->ea, lsa | (addr & 0xf));
|
||||
}
|
||||
|
||||
if (size)
|
||||
@ -346,7 +349,7 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
|
||||
case MFC_PUTR_CMD: // ???
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x, cmd=0x%x",
|
||||
(op & MFC_PUT_CMD ? "PUT" : "GET"),
|
||||
(op & MFC_RESULT_MASK ? "R" : ""),
|
||||
(op & MFC_BARRIER_MASK ? "B" : ""),
|
||||
@ -362,7 +365,7 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
|
||||
case MFC_PUTRL_CMD: // ???
|
||||
case MFC_GETL_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa=0x%x, list=0x%llx, tag=0x%x, size=0x%x, cmd=0x%x",
|
||||
(op & MFC_PUT_CMD ? "PUT" : "GET"),
|
||||
(op & MFC_RESULT_MASK ? "RL" : "L"),
|
||||
(op & MFC_BARRIER_MASK ? "B" : ""),
|
||||
@ -378,39 +381,16 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
|
||||
case MFC_PUTLLUC_CMD:
|
||||
case MFC_PUTQLLUC_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x",
|
||||
if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x, cmd=0x%x",
|
||||
(op == MFC_GETLLAR_CMD ? "GETLLAR" :
|
||||
op == MFC_PUTLLC_CMD ? "PUTLLC" :
|
||||
op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"),
|
||||
lsa, ea, tag, size, cmd);
|
||||
|
||||
if ((u32)ea != ea)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "DMA %s: Invalid external address (0x%llx)",
|
||||
(op == MFC_GETLLAR_CMD ? "GETLLAR" :
|
||||
op == MFC_PUTLLC_CMD ? "PUTLLC" :
|
||||
op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"),
|
||||
ea);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
if (op == MFC_GETLLAR_CMD) // get reservation
|
||||
{
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
|
||||
vm::reservation_acquire(vm::get_ptr(ls_offset + lsa), vm::cast(ea), 128, [this]()
|
||||
{
|
||||
//std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(tid);
|
||||
|
||||
//if (t && (t->GetType() == CPU_THREAD_SPU || t->GetType() == CPU_THREAD_RAW_SPU))
|
||||
//{
|
||||
// SPUThread& spu = static_cast<SPUThread&>(*t);
|
||||
|
||||
// spu.m_events |= SPU_EVENT_LR; // TODO: atomic op
|
||||
// spu.Notify();
|
||||
//}
|
||||
|
||||
m_events |= SPU_EVENT_LR; // TODO: atomic op
|
||||
Notify();
|
||||
});
|
||||
@ -448,16 +428,16 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_ERROR(Log::SPU, "Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||
op, cmd, lsa, ea, tag, size);
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "Unknown MFC cmd (opcode=0x%x, cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x)", op, cmd, lsa, ea, tag, size);
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SPUThread::CheckEvents()
|
||||
{
|
||||
// checks events:
|
||||
|
||||
return (m_events & m_event_mask) != 0;
|
||||
}
|
||||
|
||||
|
@ -297,7 +297,7 @@ bool DynamicMemoryBlockBase::AllocFixed(u32 addr, u32 size)
|
||||
|
||||
for (u32 i = 0; i<m_allocated.size(); ++i)
|
||||
{
|
||||
if (addr >= m_allocated[i].addr && addr < m_allocated[i].addr + m_allocated[i].size) return false;
|
||||
if (addr >= m_allocated[i].addr && addr <= m_allocated[i].addr + m_allocated[i].size - 1) return false;
|
||||
}
|
||||
|
||||
AppendMem(addr, size);
|
||||
@ -342,8 +342,8 @@ u32 DynamicMemoryBlockBase::AllocAlign(u32 size, u32 align)
|
||||
|
||||
for (u32 i = 0; i<m_allocated.size(); ++i)
|
||||
{
|
||||
if ((addr >= m_allocated[i].addr && addr < m_allocated[i].addr + m_allocated[i].size) ||
|
||||
(m_allocated[i].addr >= addr && m_allocated[i].addr < addr + exsize))
|
||||
if ((addr >= m_allocated[i].addr && addr <= m_allocated[i].addr + m_allocated[i].size - 1) ||
|
||||
(m_allocated[i].addr >= addr && m_allocated[i].addr <= addr + exsize - 1))
|
||||
{
|
||||
is_good_addr = false;
|
||||
addr = m_allocated[i].addr + m_allocated[i].size;
|
||||
|
@ -271,7 +271,7 @@ namespace vm
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reservation_query(u32 addr, bool is_writing)
|
||||
bool reservation_query(u32 addr, u32 size, bool is_writing)
|
||||
{
|
||||
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
||||
|
||||
@ -282,8 +282,30 @@ namespace vm
|
||||
|
||||
if (is_writing)
|
||||
{
|
||||
// break the reservation
|
||||
_reservation_break(addr);
|
||||
assert(size);
|
||||
|
||||
if (addr + size - 1 >= g_reservation_addr && g_reservation_addr + g_reservation_size - 1 >= addr)
|
||||
{
|
||||
// break the reservation if writing access and reservation overlap
|
||||
_reservation_break(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// full-size check (isn't accurate enough)
|
||||
if (!check_addr(addr, size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// assume that the same memory page is accessed (isn't accurate enough)
|
||||
if (g_reservation_addr >> 12 != addr >> 12)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// write memory using "privileged" access to avoid breaking reservation
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -39,7 +39,7 @@ namespace vm
|
||||
// attempt to atomically update reserved memory
|
||||
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, u32 size, bool is_writing);
|
||||
// for internal use
|
||||
void reservation_free();
|
||||
// perform complete operation
|
||||
|
Loading…
Reference in New Issue
Block a user