How To Access SCTLR_EL1 of Non Secure World From EL3

I found this documentation: https://cs140e.sergio.bz/docs/ARMv8-Reference-Manual.pdf

On page D7-2464, it mentions that SCTLR_EL1 of the Non-Secure world can be accessed from EL3.

I am using ARMv8 FVP.

Can anyone provide guidance on how to access and update SCTLR_EL1 of the Non-Secure world (Linux)  from EL3?

  • You should probably be getting the Arm Architecture Reference Manual from the Arm website rather than a third-party.

    That's not quite what the quoted section is saying.  When EL3 is using AArch64, SCTLR_EL1 is not banked in hardware.  There's one copy of the register used in both Secure and Non-secure (and later Realm) state.  It's up to EL3 software to save/restore the register when execution moves between Security states.

    There are a small number of hardware banked registers in AArch64, mostly connected to the GIC.  For those hardware banked registers, which copy EL3 "sees" is based on the current value of SCR_EL3.NS.  Note, you'd need an ISB (or other context sync event) between writing the SCR_EL3.NS bit and then accessing the selected bank copy of the register.

    Also note, when EL3 is using AArch32 the equivalent register (SCTLR) is hardware banked.

  • Thank you for your reply.
    However, I am getting different values in EL1 and EL3 for same register.

    I used the MRS instruction to read SCTLR_EL1 from Linux (EL1), and then I used the same MRS instruction from EL3 to read SCTLR_EL1.
    But the value I got from EL3 is different from the value I got from EL1. Why is that?

    I implemented a system call in which I read SCTLR_EL1, then performed an SMC, and read the same register from EL3.
    I tried reading it from various places in trusted firmware (from runtime_exception.S, Context.S), but I never got the same value in EL3 as in EL1.

  • Without knowing more, some guesses:

    • While in Linux, SCTLR_EL1 changes between your MRS and the SMC
      • If the MRS and SMC aren't close together, or they're wrapped in kernel calls, that's perhaps more likely - but I'm not a Linux expert.
    • Your OS is running in EL2, not EL1, with E2H set to 1.
      • In that case, accesses at EL2 to _EL1 registers will (in some cases) be re-directed to the equivalent _EL2 register.  The same re-direction does not happen at EL3.  So your MRS in the kernel (at EL2) and in firmware (at EL3) genuinely are to different registers.
    • Your OS is running in EL1 as a VM under a hypervisor
      • In that case, the SMC will likely initially go to the hypervisor, not firmware.  What the hypervisor then does I don't know, but it could lead to SCTLR_EL1 being updated.
    • Between arriving in EL3 and reading SCTLR_EL1 some other code is running, for example save/restore code, that overwrites SCTLR_EL1.  
  • Thank You for your reply. Yes, the OS was running in EL2, and I was able to write to it using the sctlr_el2 register. Thank You for your guidance.