target-arm: Fix resetting issues on ARMv7-M CPUs
When calling qemu_system_reset after startup on a Cortex-M CPU, the initial values of PC, MSP and the Thumb bit weren't being set correctly if the vector table was in ROM. In particular, since Thumb was 0, a Usage Fault would arise immediately after trying to execute any instruction on a Cortex-M. Signed-off-by: Martin Galvan <martin.galvan@tallertechnologies.com> Message-id: CAOKbPbaLt-LJsAKkQdOE0cs9Xx4OWrUfpDhATXPSdtuNw2xu_A@mail.gmail.com [PMM: removed an incorrect comment] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
							parent
							
								
									bfb27e6042
								
							
						
					
					
						commit
						6e3cf5df01
					
				@ -129,22 +129,34 @@ static void arm_cpu_reset(CPUState *s)
 | 
				
			|||||||
    env->uncached_cpsr = ARM_CPU_MODE_SVC;
 | 
					    env->uncached_cpsr = ARM_CPU_MODE_SVC;
 | 
				
			||||||
    env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
 | 
					    env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
 | 
				
			||||||
    /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
 | 
					    /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
 | 
				
			||||||
       clear at reset.  Initial SP and PC are loaded from ROM.  */
 | 
					     * clear at reset. Initial SP and PC are loaded from ROM.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    if (IS_M(env)) {
 | 
					    if (IS_M(env)) {
 | 
				
			||||||
        uint32_t pc;
 | 
					        uint32_t initial_msp; /* Loaded from 0x0 */
 | 
				
			||||||
 | 
					        uint32_t initial_pc; /* Loaded from 0x4 */
 | 
				
			||||||
        uint8_t *rom;
 | 
					        uint8_t *rom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        env->daif &= ~PSTATE_I;
 | 
					        env->daif &= ~PSTATE_I;
 | 
				
			||||||
        rom = rom_ptr(0);
 | 
					        rom = rom_ptr(0);
 | 
				
			||||||
        if (rom) {
 | 
					        if (rom) {
 | 
				
			||||||
            /* We should really use ldl_phys here, in case the guest
 | 
					            /* Address zero is covered by ROM which hasn't yet been
 | 
				
			||||||
               modified flash and reset itself.  However images
 | 
					             * copied into physical memory.
 | 
				
			||||||
               loaded via -kernel have not been copied yet, so load the
 | 
					             */
 | 
				
			||||||
               values directly from there.  */
 | 
					            initial_msp = ldl_p(rom);
 | 
				
			||||||
            env->regs[13] = ldl_p(rom) & 0xFFFFFFFC;
 | 
					            initial_pc = ldl_p(rom + 4);
 | 
				
			||||||
            pc = ldl_p(rom + 4);
 | 
					        } else {
 | 
				
			||||||
            env->thumb = pc & 1;
 | 
					            /* Address zero not covered by a ROM blob, or the ROM blob
 | 
				
			||||||
            env->regs[15] = pc & ~1;
 | 
					             * is in non-modifiable memory and this is a second reset after
 | 
				
			||||||
 | 
					             * it got copied into memory. In the latter case, rom_ptr
 | 
				
			||||||
 | 
					             * will return a NULL pointer and we should use ldl_phys instead.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            initial_msp = ldl_phys(s->as, 0);
 | 
				
			||||||
 | 
					            initial_pc = ldl_phys(s->as, 4);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        env->regs[13] = initial_msp & 0xFFFFFFFC;
 | 
				
			||||||
 | 
					        env->regs[15] = initial_pc & ~1;
 | 
				
			||||||
 | 
					        env->thumb = initial_pc & 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (env->cp15.c1_sys & SCTLR_V) {
 | 
					    if (env->cp15.c1_sys & SCTLR_V) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user