-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AArch64: Rework secure states (NS vs S) discussion #32492
Comments
Tagging the relevant people: @npitre @jharris-intel @MrVan @ioannisg @stephanosio @Abhishek-brcm @sandeepbrcm |
For reference, with QEMU, there's actually more than two different possibilities there.
EL3 is always secure, EL2 is always non-secure, so the real direct changes in the above are roughly:
...with the added wrinkle that switches between secure/nonsecure can only happen when going through EL3. (I wish ARM allowed a secure EL1 to directly interact with a nonsecure EL0...) |
As for the impact of this and your questions...
I think so, see my previous comment. You can get QEMU to start in all of the supported configurations, and between that and maybe writing a thin secure monitor for testing purposes you should be good.
I think this should be more "we should introduce CPU flags for if the core (from our perspective) supports security / virtualization, on top of the existing CONFIG_ARMV8_A_NS / CONFIG_ARMV8_A_S". So roughly: Core supports the security extensions? Great, then we can choose between (With a wrinkle here that it's not so much "core supports" as "we have control over". You could have a core with EL3, running a secure monitor outside our control, where Zephyr is only in control of EL1 and below...) There is one other long-tail "nice-to-have", which is to write a quick secure monitor / hypervisor, to allow testing of such cases, but honestly I don't think it's worth it.
Roughly speaking: There is a (...mostly) standard power-management protocol for ARM cores. The defined protocol is to do Annoyingly, PSCI is entirely defined for the non-secure world, and e.g. is designed to boot CPU cores into non-secure state. What this means is roughly that PSCI (the standard) only works if Zephyr is running in non-secure state, or if there's some platform-defined manner to switch between secure and non-secure state. My suggestion for SMP CPU management here is to just define a standard interface for starting a core / stopping a core / suspending a core (optionally) / resuming a core, with the interface for AArch64 requiring that the core starts in the appropriate mode (the same EL and security state as Zephyr starts up in). Then the standard PSCI interface can be an implementation of this interface, gated behind |
As an aside, regardless of whichever PSCI decision is made, can we comply with the Linux kernel's devicetree spec for PSCI? https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/psci.txt |
At least until you want to support
Ok, something like
Agree. It is really weird to me that currently we force QEMU to start from
Yes, this is one of the reason why I decided to rewrite the boot code in C in #32394, so that we can easily implement these kind of checks more easily. In general I want to avoid creating too many symbols to be defined at compile time and doing as much as possible a "smart detection" of what's implemented on the core at run-time.
The only interface currently available goes through PSCI Lines 52 to 57 in 692398d
We comply already with PSCI v1.0 where the only thing you specify in the DT is the conduit. Anything missing? |
Oh interesting. I must admit I'm unfamiliar with the ARMv8.x extensions for the most part.
I mean, not quite? The interface is obviously designed as a wrapper around PSCI, and the current sole in-tree implementation does so, but it's mostly generic enough that you can write a backend driver implementation that doesn't actually use PSCI (and indeed I did so locally.) (Or to put it another way, I'd argue that the current PSCI interface is misnamed and really should be a cpu power control interface, with the current driver being a PSCI-based implementation of said interface. Similar to how there's a serial interface, and uart drivers for said serial interface...)
We don't support old PSCI versions - which honestly is likely fine and fairly easily extendable in the driver implementation if/when someone wants it. The main part there is documenting that "hey, we'd like to match the Linux kernel here".
+1 from me for this for the most part. The one thing I'll note is that if you've got a platform with a very minimal core (that e.g. have nothing above EL1) it's likely to be coresize-constrained also. But really, cross that bridge if/when we come to it... |
Supporting All permutation to enter Zephyr is going to increase complexity. I would suggest to defer such support without practical motivation unless you have time to support them all :) 1-Zephyr starts @ EL3 and drops to secure El1 and runs in secure state. TZ neutral system 2-Zephyr starts @ NS EL1 (or NS EL2) and continues in NS state and obviously in this case it can be expected (mandated) to have a EL3 runtime to provide the secure services like PSCI. It is unlikely that SoC will have core control sequences available to NS state. Zephyr can leave it to platform choice though. I feel the PSCI usage issue can be easily sorted with a thin wrapper for cpu ops. |
But this is what we already have in place. Case (1) is the case
Ok, let's take this step-by-step then. I'll try to prepare a patch to migrate the CPU ops interface / subsystem from PSCI to a more generic interface and then we can proceed from there. |
here #32673 |
The current situation for the NS vs S story in Zephyr for AArch64 is very confusing (at lest to me) and I feel the urgency to fix it ASAP because the port is quickly growing in size and complexity.
This is the current status:
When Zephyr is started from
EL3
theSCR_EL3.NS
is always set to0
.This is currently done on master:
zephyr/arch/arm/core/aarch64/reset.S
Lines 102 to 104 in decf521
This means that we drop into
EL1.S
without going throughEL2
.The same is done in the reset rework at aarch64: Refactor cpu.h and move reset routine to C #32394 but we go through
EL2.S
if this is implemented, see:https:/zephyrproject-rtos/zephyr/blob/6d7859bbce51a7cc428b616d5d20bf300ab8c558/arch/arm/core/aarch64/reset.c#L133
We have in place a symbol
CONFIG_ARMV8_A_NS
that is doing basically three things: (a) setting up the GIC to deal with NS, (b) changing the MMU permission bit (b) forcing QEMU to start emulating fromEL1
. You usually want to use this symbol on real hardware when you have a secure monitor running already because the Zephyr entry point is usually done atEL1
.The point is that
CONFIG_ARMV8_A_NS
is not acting at all on theSCR_EL3.NS
bit, that means that we are not actually changing the security state, we are only making the GIC playing nicely when Zephyr is entered atEL1.NS
.The first obvious change is to toggle
SCR_EL3.NS
in accordance withCONFIG_ARMV8_A_NS
. But I want to discuss some other open points also because I'm not familiar with the nuances of NS vs S:CONFIG_ARMV8_A_NS
also forceQEMU
to start fromEL1
(as is today) or should we introduce some other symbol for that?Anyway before implementing any change I'm going to wait for #32394 to be merged.
The text was updated successfully, but these errors were encountered: