January 7, 2022

Orange Pi 4 (Rockchip 3399) AArch64 ARM execution levels

In 64 bit mode, the processor can run at any one of 4 "execution levels". Level 3 is the most privileged and level 0 might be for "user code". So typically level 3 and/or 2 are reserved for some kind of hypervisor, level 1 would be used by an operating system, and level 0 for user code.

32 bit ARM has only 2 levels (user and supervisor). Note that it is possible for a 64 bit operating system to run 32 bit user code (but not for a 32 bit operating system to run 64 bit user code).

Execution level can only change when the processor takes an exception. This is certainly the right thing when we want an event in user code to cause an exception to be handled by the operating system. Causing an intentional transition to a less privileged level (as when an operating system starts user code running) involves some trickery.

So .. what are we running in

I performed some experiments. We are running in EL 2 (not 3) which suggests that some hypervisor is running in EL 3. I did the some experiment for the Allwinner h5 code and found the same thing. I also attempted to access the SCR_EL3 register, but this yields a fault. I was doing this to learn whether or not I was in "secure mode" (see below). A fault is to be expected, given that I am trying to access an EL3 register from EL2. There is no corresponding register for EL2. If I was able to inspect this register, that would tell me if I was in secure mode or not. I use some inline assembly to look at these registers, as in the following:
static inline unsigned int
get_el(void)
{
        unsigned int val;

        asm volatile("mrs %0, CurrentEL" : "=r" (val) : : "cc");
        return val >> 2;
}
So my conclusion? I am running at EL 2 and almost certainly not in secure mode.

Secure versus Non-secure

This is an entirely different business that you would think might be handled by the execution level business above, but isn't. In fact people like to say that this secure/non-secure business is orthogonal to the execution level business described above. The ARM people call this "trust zone", which sounds a lot like a marketing name to me.

Note that "trust zone" is available (though rare in my experience) as an option for 32 bit ARM processors. It seems all but ubiquitous in the 64 bit ARM world.

A processor boots up in "secure mode", which can access both secure and non-secure resources. It can divide the memory map into secure and non-secure regions. Once it switches to non-secure mode, the secure regions will not be accessible.

The on chip bootrom in some chips protects itself and then switches to the non-secure mode before transfering control to the loaded bootloader. This makes it impossible to:
  1. Examine the bootloader itself.
  2. Perform any experiments or configuration of secure mode.
A chip like this would simply be leveraging the marketing hype about "TrustZone" without making it available for any practical use (such as storing encryption keys or such).

Interestingly a processor in non-secure mode cannot detect whether or not it is running in secure mode or not. There is an SCR register, but attempting to access it will yield an exception in non-secure mode (that should tell you if you are running in secure mode or not, eh?). You get something like a undefined exception trap. Note that the SCR is called SCR_EL3 most likely. It apparently exists only in EL3.


Have any comments? Questions? Drop me a line!

Tom's electronics pages / [email protected]