Merge pull request #1063 from FioraAeterna/fastermmufix
MMU: properly check MEM1 range on Gamecube games
This commit is contained in:
commit
74f8a48ee6
|
@ -108,6 +108,7 @@ void Jit64::lXXx(UGeckoInstruction inst)
|
||||||
|
|
||||||
// do our job at first
|
// do our job at first
|
||||||
s32 offset = (s32)(s16)inst.SIMM_16;
|
s32 offset = (s32)(s16)inst.SIMM_16;
|
||||||
|
gpr.BindToRegister(a, true, false);
|
||||||
gpr.BindToRegister(d, false, true);
|
gpr.BindToRegister(d, false, true);
|
||||||
SafeLoadToReg(gpr.RX(d), gpr.R(a), accessSize, offset, CallerSavedRegistersInUse(), signExtend);
|
SafeLoadToReg(gpr.RX(d), gpr.R(a), accessSize, offset, CallerSavedRegistersInUse(), signExtend);
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,7 @@ void Jit64::lfXXX(UGeckoInstruction inst)
|
||||||
|
|
||||||
FALLBACK_IF((!indexed && !a) || (update && a == d));
|
FALLBACK_IF((!indexed && !a) || (update && a == d));
|
||||||
|
|
||||||
if (update)
|
gpr.BindToRegister(a, true, update);
|
||||||
gpr.BindToRegister(a, true, true);
|
|
||||||
|
|
||||||
s32 offset = 0;
|
s32 offset = 0;
|
||||||
OpArg addr = gpr.R(a);
|
OpArg addr = gpr.R(a);
|
||||||
|
|
|
@ -250,6 +250,45 @@ void EmuCodeBlock::MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FixupBranch EmuCodeBlock::CheckIfSafeAddress(X64Reg reg_value, X64Reg reg_addr, u32 registers_in_use, u32 mem_mask)
|
||||||
|
{
|
||||||
|
registers_in_use |= (1 << reg_addr);
|
||||||
|
registers_in_use |= (1 << reg_value);
|
||||||
|
|
||||||
|
// Get ourselves a free register; try to pick one that doesn't involve pushing, if we can.
|
||||||
|
X64Reg scratch = RSCRATCH;
|
||||||
|
if (!(registers_in_use & (1 << RSCRATCH)))
|
||||||
|
scratch = RSCRATCH;
|
||||||
|
else if (!(registers_in_use & (1 << RSCRATCH_EXTRA)))
|
||||||
|
scratch = RSCRATCH_EXTRA;
|
||||||
|
else
|
||||||
|
scratch = reg_addr;
|
||||||
|
|
||||||
|
// On Gamecube games with MMU, do a little bit of extra work to make sure we're not accessing the
|
||||||
|
// 0x81800000 to 0x83FFFFFF range.
|
||||||
|
// It's okay to take a shortcut and not check this range on non-MMU games, since we're already
|
||||||
|
// assuming they'll never do an invalid memory access.
|
||||||
|
// The slightly more complex check needed for Wii games using the space just above MEM1 isn't
|
||||||
|
// implemented here yet, since there are no known working Wii MMU games to test it with.
|
||||||
|
if (jit->js.memcheck && !SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
|
||||||
|
{
|
||||||
|
if (scratch == reg_addr)
|
||||||
|
PUSH(scratch);
|
||||||
|
else
|
||||||
|
MOV(32, R(scratch), R(reg_addr));
|
||||||
|
AND(32, R(scratch), Imm32(0x3FFFFFFF));
|
||||||
|
CMP(32, R(scratch), Imm32(0x01800000));
|
||||||
|
if (scratch == reg_addr)
|
||||||
|
POP(scratch);
|
||||||
|
return J_CC(CC_AE, farcode.Enabled());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TEST(32, R(reg_addr), Imm32(mem_mask));
|
||||||
|
return J_CC(CC_NZ, farcode.Enabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress, int accessSize, s32 offset, u32 registersInUse, bool signExtend, int flags)
|
void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress, int accessSize, s32 offset, u32 registersInUse, bool signExtend, int flags)
|
||||||
{
|
{
|
||||||
if (!jit->js.memcheck)
|
if (!jit->js.memcheck)
|
||||||
|
@ -333,46 +372,37 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OpArg addr_loc = opAddress;
|
_assert_msg_(DYNA_REC, opAddress.IsSimpleReg(), "Incorrect use of SafeLoadToReg (address isn't register or immediate)");
|
||||||
|
X64Reg reg_addr = opAddress.GetSimpleReg();
|
||||||
if (offset)
|
if (offset)
|
||||||
{
|
{
|
||||||
addr_loc = R(RSCRATCH);
|
reg_addr = RSCRATCH;
|
||||||
if (opAddress.IsSimpleReg())
|
|
||||||
{
|
|
||||||
LEA(32, RSCRATCH, MDisp(opAddress.GetSimpleReg(), offset));
|
LEA(32, RSCRATCH, MDisp(opAddress.GetSimpleReg(), offset));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
MOV(32, R(RSCRATCH), opAddress);
|
|
||||||
ADD(32, R(RSCRATCH), Imm32(offset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST(32, addr_loc, Imm32(mem_mask));
|
|
||||||
|
|
||||||
FixupBranch slow, exit;
|
FixupBranch slow, exit;
|
||||||
slow = J_CC(CC_NZ, farcode.Enabled());
|
slow = CheckIfSafeAddress(reg_value, reg_addr, registersInUse, mem_mask);
|
||||||
UnsafeLoadToReg(reg_value, addr_loc, accessSize, 0, signExtend);
|
UnsafeLoadToReg(reg_value, R(reg_addr), accessSize, 0, signExtend);
|
||||||
if (farcode.Enabled())
|
if (farcode.Enabled())
|
||||||
SwitchToFarCode();
|
SwitchToFarCode();
|
||||||
else
|
else
|
||||||
exit = J(true);
|
exit = J(true);
|
||||||
SetJumpTarget(slow);
|
SetJumpTarget(slow);
|
||||||
|
|
||||||
size_t rsp_alignment = (flags & SAFE_LOADSTORE_NO_PROLOG) ? 8 : 0;
|
size_t rsp_alignment = (flags & SAFE_LOADSTORE_NO_PROLOG) ? 8 : 0;
|
||||||
ABI_PushRegistersAndAdjustStack(registersInUse, rsp_alignment);
|
ABI_PushRegistersAndAdjustStack(registersInUse, rsp_alignment);
|
||||||
switch (accessSize)
|
switch (accessSize)
|
||||||
{
|
{
|
||||||
case 64:
|
case 64:
|
||||||
ABI_CallFunctionA((void *)&Memory::Read_U64, addr_loc);
|
ABI_CallFunctionR((void *)&Memory::Read_U64, reg_addr);
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
ABI_CallFunctionA((void *)&Memory::Read_U32, addr_loc);
|
ABI_CallFunctionR((void *)&Memory::Read_U32, reg_addr);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
ABI_CallFunctionA((void *)&Memory::Read_U16_ZX, addr_loc);
|
ABI_CallFunctionR((void *)&Memory::Read_U16_ZX, reg_addr);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
ABI_CallFunctionA((void *)&Memory::Read_U8_ZX, addr_loc);
|
ABI_CallFunctionR((void *)&Memory::Read_U8_ZX, reg_addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment);
|
ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment);
|
||||||
|
@ -478,8 +508,7 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
|
||||||
bool swap = !(flags & SAFE_LOADSTORE_NO_SWAP);
|
bool swap = !(flags & SAFE_LOADSTORE_NO_SWAP);
|
||||||
|
|
||||||
FixupBranch slow, exit;
|
FixupBranch slow, exit;
|
||||||
TEST(32, R(reg_addr), Imm32(mem_mask));
|
slow = CheckIfSafeAddress(reg_value, reg_addr, registersInUse, mem_mask);
|
||||||
slow = J_CC(CC_NZ, farcode.Enabled());
|
|
||||||
UnsafeWriteRegToReg(reg_value, reg_addr, accessSize, 0, swap);
|
UnsafeWriteRegToReg(reg_value, reg_addr, accessSize, 0, swap);
|
||||||
if (farcode.Enabled())
|
if (farcode.Enabled())
|
||||||
SwitchToFarCode();
|
SwitchToFarCode();
|
||||||
|
|
|
@ -76,6 +76,7 @@ public:
|
||||||
void LoadAndSwap(int size, Gen::X64Reg dst, const Gen::OpArg& src);
|
void LoadAndSwap(int size, Gen::X64Reg dst, const Gen::OpArg& src);
|
||||||
void SwapAndStore(int size, const Gen::OpArg& dst, Gen::X64Reg src);
|
void SwapAndStore(int size, const Gen::OpArg& dst, Gen::X64Reg src);
|
||||||
|
|
||||||
|
Gen::FixupBranch CheckIfSafeAddress(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, u32 registers_in_use, u32 mem_mask);
|
||||||
void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset = 0, bool signExtend = false);
|
void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset = 0, bool signExtend = false);
|
||||||
void UnsafeLoadRegToRegNoSwap(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset, bool signExtend = false);
|
void UnsafeLoadRegToRegNoSwap(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset, bool signExtend = false);
|
||||||
// these return the address of the MOV, for backpatching
|
// these return the address of the MOV, for backpatching
|
||||||
|
|
Loading…
Reference in New Issue