hrydgard / ppsspp

A PSP emulator for Android, Windows, Mac and Linux, written in C++. Want to contribute? Join us on Discord at https://discord.gg/5NJB6dD or just send pull requests / issues. For discussion use the forums at forums.ppsspp.org.
https://www.ppsspp.org
Other
11.16k stars 2.17k forks source link

MTX Mototrax don't work in JIT (self modifying code) #6544

Open sum2012 opened 10 years ago

sum2012 commented 10 years ago

v0.9.8-1591-gef4847b Jit log: https://drive.google.com/file/d/0B3OaSdeV0L8kdVlSUHNiZVJOU2M/edit?usp=sharing interpreter log: https://drive.google.com/file/d/0B3OaSdeV0L8kVFB3VGZPcWthR2c/edit?usp=sharing

unknownbrackets commented 10 years ago

ARM as well? Does disabling any of the Comp* files help (swapping CONDITIONAL_DISABLE defines)?

-[Unknown]

sum2012 commented 10 years ago

Where is in the file ?

Does disabling any of the Comp* files help

sum2012 commented 10 years ago

Test in lg nexus 5 also work in interpreter .

unknownbrackets commented 10 years ago

Well, what I meant is, if it's a jit bug, it may be specific to x86jit (e.g. it may work fine on ARM with jit enabled.)

Anyway: https://github.com/hrydgard/ppsspp/blob/27870aa5935d48f9a2292450aa0504c434f5f0f6/Core/MIPS/x86/CompALU.cpp#L40

If you swap the CONDITIONAL_DISABLE define lines there, it'll disable the parts of jit in that file. Most of the Comp*.cpp files in that same directory have this. If you turn them all off, jit is "basically" disabled, except the core mechanics of it.

If it doesn't work even when everything is disabled, it's a "core mechanics" problem. If it does work, then it's a matter of narrowing down which file. I described this in that One Piece issue.

-[Unknown]

sum2012 commented 10 years ago

I swap in CompALU.cpp,CompVFPU.cpp,CompFPU.cpp,CompLoadStore.cpp I get a crash strace. 1 2

unknownbrackets commented 10 years ago

Hmm, it seems to be reading a vector to 0.

ReadVector((float*)Memory::GetPointer(addr), V_Quad, vt);

So, seems like it must be related to jit mechanics...

-[Unknown]

sum2012 commented 10 years ago

You must follow rule:1 game 1 issue btw:This game first you need disable JIT, Then in-game enable JIT 1

ghost commented 10 years ago

Yes, it works. But you shall switch, very quickly the lever in home position (JIT). After arrival to the finish.

ghost commented 10 years ago

JIT = ✔ CPUSpeed = 0 Full stop of a program runtime (hangup) : 2014-07-21 13 37 18 CPUSpeed = 44 Full stop of a program runtime (hangup) : screenshot_2014-07-21-12-47-40 CPUSpeed = 9 .../"Closed". screenshot_2014-07-21-13-08-28

ghost commented 10 years ago

Work and kill: screenshot_2014-10-14-19-59-53

screenshot_2014-10-14-20-00-32

HANG: screenshot_2014-10-14-20-13-56 screenshot_2014-10-14-20-14-53 http://a0.sderni.ru/d/1526000/saved_logs.zip

ghost commented 9 years ago

/proc/"cpuinfo"/ screenshot_2014-10-17-11-49-53 Processor : ARMv7 Processor rev 0 (v7l) processor : 0 BogoMIPS : 1592.52

processor : 1 BogoMIPS : 3185.04

processor : 2 BogoMIPS : 3185.04

processor : 3 BogoMIPS : 3185.04

Features : swp half thumb fastmult vfp edsp neon vfpv3 tls CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x3 CPU part : 0xc09 CPU revision : 0

Chip revision : 0020 Hardware : SMDK4x12 Revision : 000b Serial : _____//


/proc/"devices"/ Character devices: 1 mem 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 21 sg 29 fb 81 video4linux 89 i2c 108 ppp 116 alsa 128 ptm 136 pts 153 spi 180 usb 188 ttyUSB 189 usb_device 204 ttySAC 216 rfcomm 247 roccat 248 BaseRemoteCtl 249 media 250 ttyGS 251 usbmon 252 tzic 253 ump 254 rtc

Block devices: 1 ramdisk 259 blkext 7 loop 8 sd 65 sd 66 sd 67 sd 68 sd 69 sd 70 sd 71 sd 128 sd 129 sd 130 sd 131 sd 132 sd 133 sd 134 sd 135 sd 179 mmc 254 device-mapper


And ....etc... MemTotal: 1847188 kB MemFree: 237168 kB Buffers: 5672 kB Cached: 471980 kB SwapCached: 0 kB Active: 850156 kB Inactive: 364044 kB Active(anon): 739208 kB Inactive(anon): 57472 kB Active(file): 110948 kB Inactive(file): 306572 kB Unevictable: 948 kB Mlocked: 0 kB HighTotal: 1290240 kB HighFree: 67984 kB LowTotal: 556948 kB LowFree: 169184 kB SwapTotal: 0 kB SwapFree: 0 kB Dirty: 72 kB Writeback: 0 kB AnonPages: 737552 kB Mapped: 137804 kB Shmem: 59184 kB Slab: 24416 kB SReclaimable: 6816 kB SUnreclaim: 17600 kB KernelStack: 9280 kB PageTables: 14592 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 923592 kB Committed_AS: 19153204 kB VmallocTotal: 172032 kB VmallocUsed: 59104 kB VmallocChunk: 58244 kB

ghost commented 9 years ago

/system/"build.prop"/ ~


package android.os;

public class Build { public static final String BOARD; public static final String BOOTLOADER; public static final String BRAND; public static final String CPU_ABI; public static final String CPU_ABI2; public static final String DEVICE; public static final String DISPLAY; public static final String FINGERPRINT; public static final String HARDWARE; public static final String HOST; public static final String ID; public static final boolean IS_DEBUGGABLE = false; public static final String MANUFACTURER; public static final String MODEL; public static final String PRODUCT; @Deprecated public static final String RADIO; public static final String SERIAL; public static final String TAGS; public static final long TIME = 0L; public static final String TYPE; public static final String UNKNOWN = "unknown"; public static final String USER;

static { int i = 1; ID = getString("ro.build.id"); DISPLAY = getString("ro.build.display.id"); PRODUCT = getString("ro.product.name"); DEVICE = getString("ro.product.device"); BOARD = getString("ro.product.board"); CPU_ABI = getString("ro.product.cpu.abi"); CPU_ABI2 = getString("ro.product.cpu.abi2"); MANUFACTURER = getString("ro.product.manufacturer"); BRAND = getString("ro.product.brand"); MODEL = getString("ro.product.model"); BOOTLOADER = getString("ro.bootloader"); RADIO = getString("gsm.version.baseband"); HARDWARE = getString("ro.hardware"); SERIAL = getString("ro.serialno"); TYPE = getString("ro.build.type"); TAGS = getString("ro.build.tags"); FINGERPRINT = getString("ro.build.fingerprint"); TIME = 1000L * getLong("ro.build.date.utc"); USER = getString("ro.build.user"); HOST = getString("ro.build.host"); if (SystemProperties.getInt("ro.debuggable", 0) == i) {} for (;;) { IS_DEBUGGABLE = i; return; i = 0; } }

private static long getLong(String paramString) { try { long l = Long.parseLong(SystemProperties.get(paramString)); return l; } catch (NumberFormatException localNumberFormatException) {} return -1L; }

public static String getRadioVersion() { return SystemProperties.get("gsm.version.baseband", null); }

private static String getString(String paramString) { return SystemProperties.get(paramString, "unknown"); }

ghost commented 9 years ago

ro.build.host=cyanogenmod ro.build.tags=test-keys ro.product.brand=samsung ro.product.name=t03gxx ro.product.board=smdk4x12 ro.product.cpu.abi=armeabi-v7a ro.product.cpu.abi2=armeabi ro.product.manufacturer=samsung ro.product.locale.language=en ro.product.locale.region=US ro.wifi.channels= ro.board.platform=exynos4

ro.build.product is obsolete; use ro.product.device

ro.build.product=t03g ro.product.model=GT-N7100 ro.product.device=t03g

ghost commented 9 years ago

GetCPUPartInfo "/proc/cpuinfo" GetMaxCPUCore "/sys/devices/system/cpu/" screenshot_2014-10-17-13-27-11

GetMaxCPUSpeed "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" = 1600000

I don't know a code C + Hope, information will help You.

sum2012 commented 9 years ago

v0.9.9.1-1601-gf1bca47-windows-amd64 still do not work in JIT debug log: https://drive.google.com/file/d/0B3OaSdeV0L8kZWI3NkVfa0RsM1U/view?usp=sharing

sum2012 commented 8 years ago

v1.1.1-488-g368eef5 still do not work in JIT debug log: https://drive.google.com/file/d/0B3OaSdeV0L8keHdlS2RxeG9RX3c/view?usp=sharing

assumb 2

unknownbrackets commented 8 years ago

So the destination of a memcpy (which by the way, should've been replaced) is 0. It's not clear why, though.

The game is doing a lot of jit invalidations. It seems to use function 20 to sequentially flush the entire 16KB cache? If you search in the disasm for "cache" does it find anything? Maybe we can detect this and flush the jit.

-[Unknown]

sum2012 commented 8 years ago

Do you mean find in here ? I cannot find it. 1

unknownbrackets commented 8 years ago

Oh, sorry. After loading the game, click anywhere in the Disassembly window, and press Ctrl-F (find.) Then type "cache".

If you find a line that says "jal zz_sceKernelDcacheWirtebackRange", press F3. You might have to press it a few times. What I'm after will look like this:

cache func=20,s2(0x0)

That's the code I'm hoping to see, just to understand how this particular cache instruction is even used. We don't support it currently (we support other func=## values, but not 20.)

-[Unknown]

sum2012 commented 8 years ago

I think that you mean this "jr sceKernelDcacheWirtebackRange" 2

Here is the video after press F3 https://drive.google.com/file/d/0B3OaSdeV0L8kUjN6Um9NNzJaSTA/view?usp=sharing

unknownbrackets commented 8 years ago

Darn, none of those look like the right ones. Okay, new idea.

In Core/MIPS/MIPSInt.cpp, find this line:

DEBUG_LOG(CPU, "cache instruction affecting %08x : function %i", addr, func);

Change to:

DEBUG_LOG(CPU, "cache instruction affecting %08x : function %i  pc=%08x, imm=%d, rs=%d", addr, func, PC, imm, rs);

That should log where ever it's hiding. Maybe the game is even dynamically loading it later or something.

-[Unknown]

sum2012 commented 8 years ago

https://drive.google.com/file/d/0B3OaSdeV0L8kOU10bHVfR3JtRm8/view?usp=sharing

unknownbrackets commented 8 years ago

Thanks. What does the code look like near 08876ac4?

This gives me a pretty decent idea of how it's being used, though. It's also interesting that it does this in the vblank interrupt handler. I'm now thinking this is just the dcache and not jit related, based on that...

-[Unknown]

sum2012 commented 8 years ago

1

edit add below picture: 2

unknownbrackets commented 8 years ago

Does this work with the IR interpreter, or is it also broken there? As I understand, it does work with the standard interpreter.

-[Unknown]

sum2012 commented 8 years ago

Yes,standard interpreter work but IR interpreter crash. crash strace (v1.2.2-584-g5a45487) 1

unknownbrackets commented 8 years ago

Well, at least that confirms it's likely not a x86jit/etc. bug. It's some kind of block invalidation or partial write bug on the jit block system.

PC in your screenshot is logged as 0x40000000, so clearly we've jumped to the wrong place. My guess: it's writing an invalid jump and fixing it up later. We're not noticing that it fixes it up later.

For this specific use case, maybe we could handle jumps to invalid addresses specially.

To confirm my theory, look for this: https://github.com/hrydgard/ppsspp/blob/5a454877072e831d3c055676c7ae66fab13fb5ca/Core/MIPS/IR/IRJit.cpp#L121

Change that line to:

u32 newPC = IRInterpret(mips_, block->GetInstructions(), block->GetConstants(), block->GetNumInstructions());
if (!Memory::IsValidAddress(newPC)) {
    NOTICE_LOG(HLE, "That place looks dark and scary, I'm not going.  %08x", mips_->pc);
    mips_->downcount = -1;
    coreState = CORE_STEPPING;
} else {
    mips_->pc = newPC;
}

If that stops it from crashing (it'll still break and may hang, but at least you'll see the log message), then it probably confirms my theory. Then you can look at the address it prints and see the disassembly there (which may also help confirm.)

-[Unknown]

sum2012 commented 8 years ago

35:54:327 user_main N[HLE]: IR\IRJit.cpp:123 That place looks dark and scary, I'm not going. 0886ee88

2

unknownbrackets commented 8 years ago

Hm. I wonder what that block was when it was compiled.

Before these lines: https://github.com/hrydgard/ppsspp/blob/master/Core/MIPS/IR/IRFrontend.cpp#L250

Try adding:

if (em_address == 0x0886EE88) {
    logBlocks = 1;
} else {
    logBlocks = 0;
}

And then replace the part right below it with:

    if (logBlocks > 0 && dontLogBlocks == 0) {
        char temp2[256];
        NOTICE_LOG(JIT, "=============== mips %08x ===============", em_address);
        for (u32 cpc = em_address; cpc != GetCompilerPC() + 4; cpc += 4) {
            temp2[0] = 0;
            MIPSDisAsm(Memory::Read_Opcode_JIT(cpc), cpc, temp2, true);
            NOTICE_LOG(JIT, "M: %08x   %s", cpc, temp2);
        }
    }

(this way it will show up in your console / log file... ILOG just logs to the debugger.)

Does it show the same instructions as the screenshot above? If so, I guess it means ra is wrong which is a harder problem. If it shows different instructions, then it means we didn't notice the game wrote more data.

-[Unknown]

sum2012 commented 8 years ago

Yes,it show same instructions before hang,so it is harder to solve log: https://gist.github.com/sum2012/8fac6e5cb8512242139305f435ee225c

unknownbrackets commented 8 years ago

Darn. I think that means something is corrupting either sp or the memory at sp, since ra must be loading as 0x04000000.

Above that in the disassembly, I see a jr ra without any epilogue, which looks highly suspicious. Maybe the code it's running is just a remnant and was never supposed to even run. Hmm.

-[Unknown]

sum2012 commented 8 years ago

JPCSP run this game no problem. Maybe we can use it's debuger to debug ppsspp First ,I see 0886ee84 and 0886ee88 disassembly are vnop and vsync rather than two vflush . second the ra value is 0x0886a3e0 1

sum2012 commented 8 years ago

Another thing that I notice JPCSP log: 19:59:28 WARN hle.sceGe_user - user_main - hleGeListEnQueue can't enqueue duplicate list address 0x09282B00, stack 0x00000000 edit add full log: https://gist.github.com/sum2012/51e6d95bf24319b9a4369412e498e26b

@unknownbrackets I checked ppsspp doesn't have this check,JPCSP have this check for sdk > 0x02000000 https://github.com/jpcsp/jpcsp/blob/master/src/jpcsp/HLE/modules/sceGe_user.java#L391

May be we try to add this check ?

unknownbrackets commented 8 years ago
// Some call this VFPU7 (vflush/vnop/vsync), but it's not super important.

I don't think those instructions are the issue. But, definitely the ra value looks correct in Jpcsp. Something may be overwriting the memory.

We do actually have a similar check: https://github.com/hrydgard/ppsspp/blob/e95b2cf0d5920a0df2d28d27800d10c47266c9f2/GPU/GPUCommon.cpp#L248

Does the sp value match in PPSSPP? It might help to set a breakpoint at the start of this function, and then when it gets there, create a memory breakpoint at sp (0x9FFF220) to see what's overwriting it.

Another question is, does it crash the first time it runs this function, or is it not the first time?

-[Unknown]

sum2012 commented 8 years ago

Please note that only JIT (Drec) hit the address of start of this function It is not the first time crash when it runs start of this function. It often run the function when the screen change a little. It is first time run of the function of memory breakpoint at sp. (I assume that you mean that need set write setting) 1 2

unknownbrackets commented 8 years ago

It looks like it's about to load the correct value there. Yeah, I was thinking Write only (not Read.)

-[Unknown]

sum2012 commented 8 years ago

Write only 3

hrydgard commented 5 years ago

Been a while. How is this now?

sum2012 commented 5 years ago

v1.7.5-529-gb689c6822 Still crash with JIT debug log: https://drive.google.com/file/d/142o_Ax-lnl2LuGAZPufPYjBdlXPBekp2/view?usp=sharing

LunaMoo commented 5 years ago

This is kind of a duplicate of #3854, pretty much same problem, maybe even same engine and I also made similar CWCheat workaround for it in the past which simply forces refresh JIT on some function without doing anything else.

sum2012 commented 4 years ago

We might really need to invalidate staff of jpcsp of these game of modules to remove the hardcode cheat.(of course in ppsspp v11 ) jpcsp commit: https://github.com/jpcsp/jpcsp/commit/dd9b09a94404356d67bfe30173e0e62957ea5015

sum2012 commented 4 years ago

inline void hleFinishSyscall(const HLEFunction &info) { .... currentMIPS->InvalidateICache(0, 0xFFFFFFFF); gpu->InvalidateCache(0, -1, GPU_INVALIDATE_ALL); .... } The game still get invalid address.

The game might be other problem

sum2012 commented 4 years ago

MIPSInt.cpp

namespace MIPSInt { void Int_Cache(MIPSOpcode op) { int imm = (s16)(op & 0xFFFF); int rs = _RS; int addr = R(rs) + imm; int func = (op >> 16) & 0x1F;

    // It appears that a cache line is 0x40 (64) bytes, loops in games
    // issue the cache instruction at that interval.

    // These codes might be PSP-specific, they don't match regular MIPS cache codes very well
    switch (func) {
    // Icache
    case 8:
        // Invalidate the instruction cache at this address
        if (MIPSComp::jit) {
            MIPSComp::jit->InvalidateCacheAt(addr, 0x40);   

change to MIPSComp::jit->InvalidateCacheAt(addr, 8);

The game can work a lot longer, @hrydgard @unknownbrackets Do you have idea to fix ?

eur version of this game modify log:

ppsspplogmodify1.zip

modify disassemble:

1

hrydgard commented 4 years ago

That is interesting if I understand it correctly, it might be one of the few games that mess with their own code in a way our JIT can't handle, like the Tony Hawk games that we have a hack for. I have some possible plans to fix it properly but haven't decided on the right way yet. Tagging this for 1.11.

sum2012 commented 2 years ago

v1.13.1-547-g9f4a849 still need that hard code