Skip to content

Latest commit

 

History

History
226 lines (172 loc) · 9.63 KB

abi.md

File metadata and controls

226 lines (172 loc) · 9.63 KB

Crust Firmware ABI

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.

Loading the firmware

Location in SRAM

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 in platform/*/include/platform/memory.h
  • In ATF, as SUNXI_SCP_BASE in plat/allwinner/common/include/platform_def.h
  • In U-Boot, as SCP_ADDR in board/sunxi/mksunxi_fit_atf.sh

Firmware contents

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 in plat/allwinner/common/sunxi_pm.c

Loading process

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() in plat/allwinner/common/sunxi_pm.c

Communicating via SCPI

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.

Mailbox

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 in common/scpi.c
  • In ATF, as RX_CHAN/TX_CHAN in drivers/allwinner/sunxi_msgbox.c
  • In Linux, in the mboxes property of the scpi node in the device tree

SCPI mailbox notifications use the standard virtual channel number 1. This is defined:

  • In Crust, as SCPI_VIRTUAL_CHANNEL in include/lib/scpi_protocol.h
  • In ATF, as SCPI_MHU_SLOT_ID in drivers/arm/css/scpi/css_scpi.c

Shared memory

Crust supports SCPI with a message size of 256 bytes. This is hardcoded:

  • In Crust, as SCPI_MESSAGE_SIZE in include/lib/scpi_protocol.h
  • In ATF, as SCPI_SHARED_MEM_AP_TO_SCP in drivers/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 in common/scpi.c
  • In ATF, as PLAT_CSS_SCP_COM_SHARED_MEM_BASE in plat/allwinner/common/include/platform_def.h
  • In Linux, as the reg property of the scp-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.

Timeouts

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 in common/scpi.c (10ms)
  • In ATF, as MHU_TIMEOUT_ITERS in drivers/allwinner/sunxi_msgbox.c (1s)
  • In Linux, as MAX_RX_TIMEOUT in drivers/firmware/arm_scpi.c (30ms)

Concurrent use

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.

Supported commands

Crust attempts to follow the SCPI specification in advertising the list of supported commands, and implementing them according to spec.

Sending "SCP Ready"

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.

Power states

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_* in include/lib/scpi_protocol.h
  • In ATF, as scpi_power_state_t in include/drivers/arm/css/css_scpi.h

System power states are defined by the SCPI specification.

Hardware ownership

  • Crust owns the shared part and its private half of HWSPINLOCK and MSGBOX. ATF and Linux MUST NOT modify any part but the ARM private half.
  • Crust owns R_CPUCFG, R_TIMER, and R_TWD. Linux MUST NOT use them. ATF MUST NOT use them except for using R_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 and R_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 and R_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
  • Crust MAY modify PIO, R_CIR_RX, R_PIO, R_INTC, and R_UART, but only during boot or suspend, and it MUST restore the original configuration before Linux resumes.

RTC

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