What are the necessary preconditions to load a guest into EL1 from EL2?

I have successfully moved from EL3 to EL2. After doing some initialization I am trying to move from EL2 into EL1 with a very simple guest image. My process looks like:

  • Map EL1 memory into EL2
  • Copy EL1 image to RAM
  • Initialize sctlr_el1 = 0x30d00800
    • MMU disabled (bit unset)
    • I/D cache disabled (bit unset)
    • RES1 bits set
  • Initialize spsr_el2 = 0x3c9
    • Mask FIAD interrupts (0x3c0)
    • Set spsr.M to EL1h (SPx) (0x9)
  • Set elr_el2 to load address
  • Initialize hcr_el2 = 0
    • Set to zero, no intended traps back to EL2 for simplicity
  • eret

However, after the eret the machine will immediately trigger an instruction prefetch abort with FAR equal to the load address. From the looks of it, I don't think the hardware ever left EL2. In fact, esr_el2 has IL set, which indicates an illegal configuration (though I am confused as to why it did not manifest as an UNKNOWN exception (EC = 0x00) instead.

While debugging this I tried a few cases that seemed relevant:

  • Return to EL2 to load address of EL1 (fail)
  • Return to EL2 to load address in mapped EL2 memory (success)
  • Return to EL1 to load address in mapped EL2 memory (fail)
  • Return to EL1 to load address of EL1 (fail -- the "normal" case)

In all failure cases the hardware throws the same instruction abort (EC = 0x21)

Am I missing a step?

  • Without enabling stage2 translation the IPA==PA, and with the MMU turned off I was expecting it to not be a necessary step.

  • Why don't you look up code doing it? Could be bootloader or kernel. Excerpt from Uboot arch/arm/include/asm/macro.h

    .macro armv8_switch_to_el1_m, xreg1, xreg2                             
        /* Initialize Generic Timers */                                    
        mrs \xreg1, cnthctl_el2                                            
        orr \xreg1, \xreg1, #0x3    /* Enable EL1 access to timers */      
        msr cnthctl_el2, \xreg1                                            
        msr cntvoff_el2, xzr                                               
        /* Initilize MPID/MPIDR registers */                               
        mrs \xreg1, midr_el1                                               
        mrs \xreg2, mpidr_el1                                              
        msr vpidr_el2, \xreg1                                              
        msr vmpidr_el2, \xreg2                                             
        /* Disable coprocessor traps */                                    
        mov \xreg1, #0x33ff                                                
        msr cptr_el2, \xreg1    /* Disable coprocessor traps to EL2 */     
        msr hstr_el2, xzr       /* Disable coprocessor traps to EL2 */     
        mov \xreg1, #3 << 20                                               
        msr cpacr_el1, \xreg1   /* Enable FP/SIMD at EL1 */                
        /* Initialize HCR_EL2 */                                           
        mov \xreg1, #(1 << 31)      /* 64bit EL1 */                        
        orr \xreg1, \xreg1, #(1 << 29)  /* Disable HVC */                  
        msr hcr_el2, \xreg1                                                
        /* SCTLR_EL1 initialization                                        
         * setting RES1 bits (29,28,23,22,20,11) to 1                      
         * and RES0 bits (31,30,27,21,17,13,10,6) +                        
         * UCI,EE,EOE,WXN,nTWE,nTWI,UCT,DZE,I,UMA,SED,ITD,                 
         * CP15BEN,SA0,SA,C,A,M to 0                                       
        mov \xreg1, #0x0800                                                
        movk    \xreg1, #0x30d0, lsl #16                                   
        msr sctlr_el1, \xreg1                                              
        /* Return to the EL1_SP1 mode from EL2 */                          
        mov \xreg1, sp                                                     
        msr sp_el1, \xreg1      /* Migrate SP */                           
        mrs \xreg1, vbar_el2                                               
        msr vbar_el1, \xreg1    /* Migrate VBAR */                         
        mov \xreg1, #0x3c5                                                 
        msr spsr_el2, \xreg1    /* EL1_SP1 | D | A | I | F */              
        msr elr_el2, lr                                                    

More questions in this forum