Hi,
I am fairly new to ARM processor and start work with cortexA57 recently. After reading the technical manual and programmer guide , I have some questions regarding the exception level of v8.
1. How does the exception level change from one to another ?
According to the documents, the EL can only be changed on taking exception. And also when an exception happens, the EL can only changed to a higher level. Then , how is it changed from higher EL to lower EL ? For example, on reset, the processor starts at EL3, then how does it switch to execute program on the other levels ? Could anyone give an example to show how the EL changes during a boot sequence ?
2. How to get the current EL value ?
The document says the register PSTATE contains a field CurrentEL which indicates on which EL the processor is executing. Is the PSTATE register only existed in Aarch64 execution state , or it is also existed in Aarch32 ? If not, how to read current EL value from Aarch32 ?
Thanks in advance !
Best regards,
Xinwei
Hello,
You may want to check out the freely available ARM Cortex-A Series Programmer's Guide for ARMv8-A, in particular section 3.2 regarding changing exception levels.
To answer your first question, the exception level can only change on taking or returning from an exception, so to move down to EL2 from EL3, software running at EL3 needs to perform an exception return using the ERET instruction.
When performing an exception return the processor restores state using system registers, for example when returning from EL3:
And these registers are writeable, allowing the desired entrypoint and state to be programmed manually.
There are some other bits that you'll need to be aware of, such as the fact that the SCTLR_EL2.M bit has an architecturally unknown reset value. This bit determines whether the MMU is enabled at EL2, so software running at EL3 should clear it before entering EL2 for the first time; this way you avoid accidentally having the MMU enabled before EL2 has actually programmed its translation tables.
Also be aware of the SCR_EL3.RW and HCR_EL2.RW bits, which determine whether EL2 is AArch32/AArch64 and whether EL1 is AArch32/AArch64 respectively.
Again, I recommend you read through the programmer's guide that I linked above.
As a quick example of going from EL3 to EL2 for the first time after reset:
MSR SCTLR_EL2, XZR // Disable MMU at EL2 MOV X0, XZR ORR X0, X0, #(1 << 10) // .RW = 0b1 --> EL2 is AArch64 ORR X0, X0, #(1 << 0) // .NS = 0b1 --> Non-secure state MSR SCR_EL3, X0 MOV X0, XZR ORR X0, X0, #(7 << 6) // .A = .I = .F = 0b1 --> SErrors, IRQs, and FIQs will all be masked ORR X0, X0, #(0 << 4) // .M[4] = 0b0 --> Return to AArch64 state ORR X0, X0, #(1 << 3) // .M[3:1] = 0b100 --> Return to EL2 ORR X0, X0, #(1 << 0) // .M[0] = 0b1 --> Use EL2's dedicated stack pointer MSR SPSR_EL3, X0 ADRP X0, el2_entry // Program EL2 entrypoint ADD X0, X0, :lo12:el2_entry MSR ELR_EL3, X0 ERET // Perform exception return to EL2
To answer your second question, you can access a number of PSTATE fields directly as if they were system registers.
For example:
MRS X0, CurrentEL
And for masking/unmasking asynchronous exceptions:
MSR DAIFSet, 0b0011 // Mask IRQs and FIQs MSR DAIFClr, 0b0100 // Unmask SErrors
Hope that helps.
Hello Ash,
I am a current undergraduate research student, and I am working with an ARM Cortex A53 processor on the Raspberry Pi 3 platform.
Right now I am trying to change exception levels from boot (EL3 to EL1). I tried to play around with the code you posted but I am not getting any results. I then tried to use your original code to see if I can change from EL3 to EL2 instead, and I still have no results.
I have read the ARMv8 Technical Reference Manual and the ARMv8 Programmer's Guide, but am still having trouble on trying to get this code to work.
/* Disable MMU at EL2 */ msr sctlr_el2, xzr mov x0, xzr orr x0, x0, #(1 << 10) // .RW = 0b1 --> EL2 is AArch64 orr x0, x0, #(1 << 0) // .NS = 0b1 --> Non-secure status msr scr_el3, x0 mov x0, xzr orr x0, x0, #(7 << 6) // .A = .I = .F = 0b1 --> SError, IRQ, FIQ enabled // orr x0, x0, #(0 << 4) // .M[4] = 0b0 --> Return to AArch64 state orr x0, x0, #(1 << 3) // .M[3:1] = 0b100 --> Return to EL2 orr x0, x0, #(1 << 0) // .M[0] = 0b1 --> Use EL2's dedicated stack msr spsr_el3, x0 adrp x0, reset_handler // Program EL2 entrypoint add x0, x0, :lo12:reset_handler msr elr_el3, x0 /* Perform exception return to EL2 */ eret
This is the current code that I am testing.
Any help or direction to more information would be extremely helpful.
Thanks,
Rade
View all questions in Cortex-A / A-Profile forum