I am using Linaro's Android release on Juno r1. While the Android OS is running, i switched into EL3 by smc instruction. Then, in the smc handler of BL31, i want to read the value of SP_EL1 register in the Android to verify the current process in the OS. However, when i try to use inline assembly to read the register in the smc handler of BL31, I failed.
I think we have only one SP_EL1 register for both normal world and secure world. So maybe the trust firmware has saved the old SP_EL1 while entering secure world, am i correct? Then how can i get the
SP_EL1 value of the normal OS? I need it to get the information about current running process of the normal OS, or is there any other way to know which process is running in the normal OS from EL3?
Thanks so much for any help!
Hello
What do you mean when say you failed to read the register in the SMC handler? Do you mean you don't get the expected value, or that something else goes wrong?
You're correct in that Trusted Firmware might save off the register state of the Rich OS (Android), including its stack pointer, and you can see this in common/aarch64/context.S:
func el1_sysregs_context_save ... mrs x10, sp_el1 mrs x11, esr_el1 stp x10, x11, [x0, #CTX_SP_EL1] ...
func el1_sysregs_context_save
...
mrs x10, sp_el1
mrs x11, esr_el1
stp x10, x11, [x0, #CTX_SP_EL1]
But, I don't think it would actually save off and then overwrite the value of SP_EL1 unless it was trying to context switch to the Trusted OS (e.g. the TSP or OP-TEE) running at Secure-EL1.
Please can you clarify:
Cheers,
Ash
Thanks for your reply, Ash.
I checked it again. I can read the value, but the value is not like a correct value. When I tried to get the thread_info structure from the value by some mathematics calculation, the board just hang there (by overflow, i guess). However, if i do not do the mathematics and print the value instead, sometimes the value is correct. I guess maybe it is caused by my misuse?
In fact, I did not follow the design exactly. I ignored the x0 register when sending the SMC call from Android. Then in the SMC handler, the request will be handled by the unknown SMC handler. I added a function to handle all the unknown SMC request, and tried to read SP_EL1 in that function.
File: arm-tf/bl31/aarch64/runtime_exceptions.S, tag: smc_unknown
I added a bl instruction to my function before the original handle to the unknown request.
Hi meteor67,
I think there may be a little misunderstanding here of what SP_EL1 actually represents. When you use the SMC instruction to call into the Secure Monitor software, this is needfully done from an exception level EL1 or higher (EL0 does not have enough privilege to execute SMC). From a Linux kernel perspective, there are a few stack pointers in use. SP_EL1 will represent any "handler" stacks (i.e. a minimal stack used to handle exceptions) which is also true of SP_EL2 (at EL2) and SP_EL3 (at EL3). Exception handlers are expected to, at some point, switch from SP_ELx to using SP_EL0 which is intended to be a dynamically managed stack, via PSTATE.SPSel.
Stacks managed by EL1 are also needfully holding an address in the Linux virtual address space following the EL1 or EL12 translation regime which, when you are running code in EL3, you do not technically have an ability to resolve except by using the AT instruction, and decoding the result in the PAR_EL1 register. So, simply reading out SP_EL1 (which is not ever going to be the stack used by a thread) and performing a little mathematics to work out the offset of where you'd expect Linux's "struct thread_info" to lie is over-simplifying both the software and hardware architecture.
At any point in time, the Linux kernel may be using SP_EL0 to store it's own kernel stack pointer, and this will not contain any thread_info at any point. Since software will switch to (on exception) SP=>SP_ELx and then dynamically change SP=>SP_EL0 via PSTATE.SPSel, you might have a very hard time locating a particular "thread" stack depending on when the SMC instruction was executed. You would need to be able to be incredibly introspective about the location of Linux's current task list and scheduler structures to confirm, while at EL3, the "current process."
Ta,
Matt
Thanks for your reply, mwsealey.
I try to do this because I found that the kernel use SP_EL1 & ~(THREAD_SIZE - 1) to get the "struct thread_info" of the current process. As the THREAD_SIZE is a constant value, so if I can read SP_EL1 of the rich OS correctly, maybe I can get the structure i want.
As you explained, SMC could not be executed at EL0. However, the Android framework runs in EL0. To address this, I implemented a system call in the kernel and execute SMC instruction from the kernel. Then when the Android system reached some specific situation, I call the system call to trigger a switch to EL1, and EL1 then use SMC to enter EL3.
Before I involved EL3, I tried to identify the current process with similar approach in EL1, and that worked for me. So I guess maybe that should also work in EL3. After I got
the SP_EL1, maybe still I have to translate the address to a correct address in the non-secure EL1, but i guess the translation could be done by many approach.
I am not sure about this, and I just want to try to work it out. Deep appreciate for your reply!
Regards,
Zhenyu
Hi Zhenyu,
You may have to explain exactly what you tried and where in the kernel (at EL1) you tried it.
Maybe also you could explain why the stack pointer values you see in EL3 are "wrong"?
While it is all well and good to deal with the theory, sometimes the solution is only obvious when you see empirical results
Thanks, mwsealey.
To "wrong" value i mentioned is some "gibberish" characters printed on the console. And after your question, i realized that maybe I have got the correct SP_EL1, and it just appears to be "wrong" while i print them. After some debug process, I found that the SP_EL1 i got is absolutely correct.
Then i tried to find out why the correct SP_EL1 brings my code to hang. Finally i found that i missed an address translation, and attempted to access a virtual address of EL1 from EL3. After i fix that, everything goes well now. I can correctly identify the current process of rich os from EL3.
I really should debug it more deeply before ask. Thanks so much for your guide!!
View all questions in Arm Development Platforms forum