Closed CelesteBlue-dev closed 4 years ago
A friend told me: "kotcrab hasn't implemented interrupt controller instructions. You can fix that in allegrexinstructions.sinc line 746. https://github.com/kotcrab/ghidra-allegrex/blob/master/data/languages/allegrexInstructions.sinc#L746 Not sure he got implemented interrupt controller at all. This can be done as workaround by creating special register otherwise it will not gonna work for decompiler. Those opcodes are overally documented, so should be easy to add."
https://gigawiz.github.io/yapspd/html_chapters_split/chap4.html#sec4.8
Yeah, the mfic
and mtic
have wrong conditions. Is there just one interrupt register?
That would mean for mfic
rd
is always $zero
and for mtic
rt
is $zero
Though if that's the case I don't understand how this works:
mtic $a0, zero
to renable based on the original mask in a0
The MIPS 32-bit has a catch-all special2
instruction, you can add it to your files if you want:
define pcodeop special2;
:SPECIAL2 RD, RSsrc, RTsrc, sa, fct is $(AMODE) & prime=0x1C & sa & RD & RSsrc & RTsrc & fct {
tmp:1 = fct;
tmp2:1 = sa;
RD = special2(RSsrc, RTsrc, tmp2, tmp);
}
Thanks. I haven't tested anything yet, but adding more info: http://lukasz.dk/mirror/forums.ps2dev.org/viewtopic9372.html?t=13034 https://github.com/kpspemu/kpspemu/blob/44af41bf2e533822e76c213b797377e45f7f54c6/kpspemu/src/commonMain/kotlin/com/soywiz/kpspemu/cpu/Instructions.kt#L148
Another person told me "Missing a RTsrc?"
HALT: opcode 0x70000000. This instructions waits for an interruption to wake it up. MFIC: opcode 0x70000024 with mask 0xFFFF07FF. It retrieves the interrupt controller state (1: interruptions enabled, 0: interruptions disabled) into the register described by mask 0x0000F800. MTIC: opcode 0x70000026 with mask 0xFFFF07FF. It sets the interrupt controller state to the value which is in the register described by mask 0x0000F800. via: https://github.com/uofw/upspd/wiki/CPU#Special_instructions_details
MFIC instruction really use only rt, MTIC use only rs. In MTIC rt seems to be always $zero, same goes for MFIC rs. So is kinda opcode that have hardcoded IC as destination/source depend on instruction, and psp seems to always use $zero for it. This can look weird as it push value to $zero, but is like a pseudo opcode that really push it to IC instead, not to real $zero. I think that best solution will be pseudo register for interrupt controller available only from mtic, halt, mfic. Games should never reach those instructions anyway, maybe kernel.
That assume "full" support for it, workaround can be just set rt/rd in those opcodes to not rX=0. But then it will be only look nice in assembly without real value in decompilation.
Oops this got closed after merging #5 please reopen @CelesteBlue-dev if you still have this problem. I added new prebuilt version with all the latest changes https://github.com/kotcrab/ghidra-allegrex/releases/tag/v1.0
I confirm that this issue has been fixed by adding MFIC and MTIC support in #5. For comparison, now the disassembly looks like:
LAB_0000087c XREF[1]: 00000848(j)
0000087c c0 14 62 7f ext v0,k1,0x13,0x3
00000880 23 10 02 00 subu v0,zero,v0
00000884 24 10 45 00 and v0,v0,a1
00000888 f9 ff 40 04 bltz v0,LAB_00000870
0000088c 00 e0 02 24 _li v0,-0x2000
00000890 04 28 04 7c ins a0,zero,0x0,0x6
00000894 23 28 a4 00 subu a1,a1,a0
00000898 24 00 03 70 mfic v1
0000089c 21 40 40 00 move t0,v0
LAB_000008a0 XREF[1]: 000008e0(j)
000008a0 26 00 00 70 mtic zero
LAB_000008a4 XREF[1]: sceSuspendForKernel_0AB0C6F3:000
000008a4 40 00 42 24 addiu v0,v0,0x40
And decompilation does not halt anymore, giving very good results:
// ...
return 0;
}
if ((int)(-((uint)(in_k1 << 10) >> 0x1d) & param_2) < 0) {
return 0x80000104;
}
uVar1 = getInterruptMask();
iVar3 = -0x2000;
do {
setInterruptMask(0);
iVar2 = iVar3 + 0x40;
cacheOp(0x10,iVar3 + 0x2000);
getCopReg(0,TagLo);
getCopReg(0,TagHi);
setInterruptMask(uVar1);
// ...
Disassembly when loading sysmem.prx with ghidra-allegrex:
After forcing decompilation I get:
Disassembly when loading sysmem.prx with MIPS 32 bits little endian:
Even though MIPS disassembler doesn't understand these "SPECIAL" instructions, it decompiles them seeing them as instructions. This way, the function can be decompiled to pseudo-code.
With ghidra-allegrex, the pseudo-code fails to decompile the function:
When loading with MIPS 32-bits little endian: