Fix SWI handling (disable IRQs)

This introduced a potential race condition between the start of a SWI
and the BIOS handling the exception by returning to system mode. During
this ~10 instruction window, having an IRQ that issues a SWI causes bad
behaviour that results in crashes or other weirdness.
Fixes a couple of games and potentially many weird and obscure bugs here
and there (hard to reproduce sometimes).
This commit is contained in:
David Guillen Fandos 2021-09-17 22:22:01 +02:00
parent ed89923fda
commit 3cab8596b8
4 changed files with 8 additions and 5 deletions

View File

@ -410,7 +410,7 @@ defsymbl(execute_swi_##mode) ;\
add r1, reg_base, #SPSR_RAM_OFF /* r1 = spsr */;\
str r0, [r1, #(MODE_SUPERVISOR * 4)] /* spsr[MODE_SUPERVISOR] = cpsr */;\
bic r0, r0, #0x3F /* clear mode flag in r0 */;\
orr r0, r0, #0x13 /* set to supervisor mode */;\
orr r0, r0, #(0x13 | 0x80) /* supervisor mode + disable IRQ */;\
str r0, [reg_base, #REG_CPSR] /* update cpsr */;\
;\
mov r0, #MODE_SUPERVISOR ;\

6
cpu.c
View File

@ -3197,7 +3197,8 @@ arm_loop:
spsr[MODE_SUPERVISOR] = reg[REG_CPSR];
reg[REG_PC] = 0x00000008;
arm_update_pc();
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x1F) | 0x13;
// Move to ARM mode, Supervisor mode and disable IRQs
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13 | 0x80;
set_cpu_mode(MODE_SUPERVISOR);
break;
}
@ -3682,7 +3683,8 @@ thumb_loop:
spsr[MODE_SUPERVISOR] = reg[REG_CPSR];
reg[REG_PC] = 0x00000008;
thumb_update_pc();
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13;
// Move to ARM mode, Supervisor mode and disable IRQs
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13 | 0x80;
set_cpu_mode(MODE_SUPERVISOR);
collapse_flags();
goto arm_loop;

View File

@ -409,7 +409,7 @@ defsymbl(execute_swi)
sw $2, SUPERVISOR_SPSR($16) # save cpsr in SUPERVISOR_CPSR
srl $2, $2, 6 # zero out bottom 6 bits of CPSR
sll $2, $2, 6
ori $2, 0x13 # set mode to supervisor
ori $2, (0x13 | 0x80) # mode supervisor + disable IRQs
sw $2, REG_CPSR($16) # write back CPSR
save_registers
li $4, 3 # 3 is supervisor mode

View File

@ -2179,7 +2179,8 @@ static void function_cc execute_swi(u32 pc)
bios_read_protect = 0xe3a02004;
reg_mode[MODE_SUPERVISOR][6] = pc;
spsr[MODE_SUPERVISOR] = reg[REG_CPSR];
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13;
// Move to ARM mode, supervisor mode, disable IRQs
reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13 | 0x80;
set_cpu_mode(MODE_SUPERVISOR);
}