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:
		
							parent
							
								
									ed89923fda
								
							
						
					
					
						commit
						3cab8596b8
					
				
					 4 changed files with 8 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -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
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								cpu.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue