Crust, and any firmware that wishes to be compatible with it, interacts with other third-party software and firmware components at several ABI boundaries. Some of those boundaries were arbitrarily chosen, and are now hardcoded in various places throughout the ecosystem. This document attempts to enumerate those boundaries and provide the rationale for choosing them.
Crust is loaded into SRAM A2, because that is the SRAM region in the same power domain as the AR100. It is also the SRAM region containing the AR100 exception vector area.
On platforms that use ATF (A64/H5/H6), Crust is allocated the last 16KiB of SRAM A2. 16KiB was chosen as the smallest size that an SCP firmware could feasibly be made. It is simultaneously the largest amount of space that could be shaved off of ATF without breaking debug builds (it was previously using all of SRAM A2).
Crust was placed at the end of SRAM A2 to avoid changing ATF's load address. This allowed SCP firmware support to be added to ATF over the course of several months, without requiring any breaking changes.
On platforms that do not use ATF (32-bit platforms), Crust reserves the right to use the entirety of SRAM A2, if needed.
Crust's load address is hardcoded:
- In Crust, as
FIRMWARE_BASE
inplatform/*/include/platform/memory.h
- In ATF, as
SUNXI_SCP_BASE
inplat/allwinner/common/include/platform_def.h
- In U-Boot, as
SCP_ADDR
inboard/sunxi/mksunxi_fit_atf.sh
Other than the first 32-bit word, no assumptions should be made about the contents of the Crust firmware binary.
The first 32-bit word (the entry point) is stable, because it is the only way
to use a single entry point for all exception vectors. Other firmware can
assume that if the first four bytes at Crust's load address are 12 00 40 b4
,
then Crust has been loaded into SRAM. Conversely, if the bytes are any other
value, it is safe to assume that Crust has not been loaded.
This magic value is hardcoded:
- In Crust, as the first instruction in
common/start.S
- In ATF, as
SCP_FIRMWARE_MAGIC
inplat/allwinner/common/sunxi_pm.c
Crust is not loaded adjacent to the AR100 exception vector area (which is 4KiB before the beginning of "usable" SRAM A2). Therefore, the exception vectors cannot be stored inside the firmware binary, and they must be programmed separately.
Since the opcode for the l.j
(unconditional jump) instruction is 0, this is
easy. The value to write is (entry - vector) >> 2
.
This process is performed:
- In Crust, as the loop labeled "Writing exception vectors" in
tools/load.c
- In ATF, inside
plat_setup_psci_ops()
inplat/allwinner/common/sunxi_pm.c
SCPI uses two hardware interfaces: a mailbox and a shared memory area.
Crust provides two SCPI communication channels: one for ATF (secure") and one for Linux ("non-secure"). Crust reserves the right to add a third communication channel in the future for a TEE in Secure EL1. Therefore, it must be assumed to use three pairs mailbox channels and three shared memory segments.
SCP firmware is responsible for enabling the mailbox clock and reset. Other mailbox drivers SHOULD enable them if they are not already enabled, but MUST NOT disable them once they are enabled.
SCP firmware is responsible for configuring the mailbox channel directions. Other mailbox drivers MUST NOT modify the channel direction registers.
Crust has reserved the first six mailbox channels for use with SCPI. While they MAY also be used for other protocols, SCPI client drivers are unlikely to handle this cleanly. Channel allocation is as follows:
Channel | Direction | Use |
---|---|---|
0 | AP → SCP | SCPI (Secure EL3) |
1 | SCP → AP | SCPI (Secure EL3) |
2 | AP → SCP | SCPI (Non-secure EL1/EL2) |
3 | SCP → AP | SCPI (Non-secure EL1/EL2) |
4 | AP → SCP | SCPI (Secure EL1) (future) |
5 | SCP → AP | SCPI (Secure EL1) (future) |
6 | AP → SCP | Unallocated |
7 | SCP → AP | Unallocated |
This allocation is defined:
- In Crust, as
RX_CHAN
/TX_CHAN
incommon/scpi.c
- In ATF, as
RX_CHAN
/TX_CHAN
indrivers/allwinner/sunxi_msgbox.c
- In Linux, in the
mboxes
property of thescpi
node in the device tree
SCPI mailbox notifications use the standard virtual channel number 1. This is defined:
- In Crust, as
SCPI_VIRTUAL_CHANNEL
ininclude/lib/scpi_protocol.h
- In ATF, as
SCPI_MHU_SLOT_ID
indrivers/arm/css/scpi/css_scpi.c
Crust supports SCPI with a message size of 256 bytes. This is hardcoded:
- In Crust, as
SCPI_MESSAGE_SIZE
ininclude/lib/scpi_protocol.h
- In ATF, as
SCPI_SHARED_MEM_AP_TO_SCP
indrivers/arm/css/scpi/css_scpi.c
Thus, each shared memory segment is 512 bytes long. Shared memory segments grow down from the top of SRAM A2, in the same order as mailbox channels grow up.
Offset | Direction | Use |
---|---|---|
-0x100 | AP → SCP | SCPI (Secure EL3) |
-0x200 | SCP → AP | SCPI (Secure EL3) |
-0x300 | AP → SCP | SCPI (Non-secure EL1/EL2) |
-0x400 | SCP → AP | SCPI (Non-secure EL1/EL2) |
-0x500 | AP → SCP | SCPI (Secure EL1) (future) |
-0x600 | SCP → AP | SCPI (Secure EL1) (future) |
These offsets are defined:
- In Crust, as
SCPI_MEM_AREA
incommon/scpi.c
- In ATF, as
PLAT_CSS_SCP_COM_SHARED_MEM_BASE
inplat/allwinner/common/include/platform_def.h
- In Linux, as the
reg
property of thescp-shmem
node in the device tree
Note that because SRAM A2 is "secure-only", Linux may not be able to access it when the secure mode fuse is blown. In that case, the non-secure shared memory will have to be moved to DRAM or SRAM A1.
Testing shows that Crust normally responds to SCPI commands within 1ms. Acknowledgment of responses is polled in ATF and interrupt-driven in Linux. In both cases, it should be at least as fast. Thus the current timeouts are very conservative. The only timeout that is sometimes too short is the ATF polling timeout, when adding many lines of serial debugging to the Crust boot process.
Timeouts are defined:
- In Crust, as
SCPI_TX_TIMEOUT
incommon/scpi.c
(10ms) - In ATF, as
MHU_TIMEOUT_ITERS
indrivers/allwinner/sunxi_msgbox.c
(1s) - In Linux, as
MAX_RX_TIMEOUT
indrivers/firmware/arm_scpi.c
(30ms)
Crust supports concurrent SCPI commands by all clients, but only one command at a time per client. No further commands from a client will be processed until the previous response is acknowledged.
Currently, neither ATF nor Linux attempts to send multiple concurrent commands on a single channel.
Crust attempts to follow the SCPI specification in advertising the list of supported commands, and implementing them according to spec.
Since the mailbox hardware in sunxi SoCs is a FIFO, not the doorbell that SCPI was designed for, it is important to avoid sending messages that will be ignored. To this end, Crust only sends the "SCP Ready" message when it believes the system is first booting.
Crust assumes the system is booting iff CPU 0 is the only running CPU. This can be wrong, for example if Crust crashed and restarted while Linux was booted and all other CPUs were offlined to save power.
It may be prudent to introduce an explicit handshake with ATF to signal first boot.
Crust uses the same CPU/CSS power states as defined in the SCPI specification appendix:
State | Meaning |
---|---|
0 | On |
1 | Retention |
2 | RESERVED |
3 | Off |
These are also defined:
- In Crust, as
SCPI_CSS_*
ininclude/lib/scpi_protocol.h
- In ATF, as
scpi_power_state_t
ininclude/drivers/arm/css/css_scpi.h
System power states are defined by the SCPI specification.
- Crust owns the shared part and its private half of
HWSPINLOCK
andMSGBOX
. ATF and Linux MUST NOT modify any part but the ARM private half. - Crust owns
R_CPUCFG
,R_TIMER
, andR_TWD
. Linux MUST NOT use them. ATF MUST NOT use them except for usingR_CPUCFG
to turn on the AR100. - Crust owns all of
R_PRCM
except the clock/reset registers. ATF and Linux MUST NOT use any registers except those controlling clocks/resets. - Crust MAY modify
R_RSB
andR_TWI
, but only during boot or suspend. Linux and ATF MUST reset these devices after resume before attempting to use them. - Crust MAY modify
RTC
, but only during boot or suspend, except for the general purpose registers, which may be modified at any time. Use of general purpose registers by ATF, Linux, or Crust MUST be documented. - Crust MAY modify
CCU
andR_PRCM
, but only during boot or suspend, and it MUST restore the original configuration before Linux resumes, except for:- The following bus clocks/resets, which Crust owns:
HWSPINLOCK
,MSGBOX
,DRAM
,R_TWD
- And the following bus clocks/resets, which Crust MAY leave disabled after
resume:
R_RSB
,R_TWI
- The following bus clocks/resets, which Crust owns:
- Crust MAY modify
PIO
,R_CIR_RX
,R_PIO
,R_INTC
, andR_UART
, but only during boot or suspend, and it MUST restore the original configuration before Linux resumes.
Crust uses the following RTC general purpose registers:
N | Use |
---|---|
0 | N/A (used by p-boot/u-boot) |
1 | N/A (used by p-boot/u-boot) |
2 | Last exception encountered |
3 | Last suspend/resume step executed |