Using the Bootloader

Unlocking and Trusty

Recommendations

All Google-branded devices should be made unlockable so that all partitions listed above can be reflashed.  This unlocked mode is set with fastboot flashing unlock, and once set this mode should persist across reboots.

Devices should deny the fastboot flashing unlock command unless fastboot flashing get_unlock_ability is: "1" If get_unlock_ability is "0" the user needs to boot to the home screen, go into the Settings > System > Developer options menu and enable the OEM unlocking option to set unlock_ability to: "1" That flag should be persistent across reboots and across factory data resets.

When the fastboot flashing unlock command is sent, the device should prompt users to warn them that they may encounter problems with unofficial images. After acknowledging, a factory data reset should be done to prevent unauthorized data access. The bootloader should reset the device even if it is not able to reformat it properly. Only after reset can the persistent flag be set so that the device can be reflashed.

The fastboot flashing lock command relocks and resets the device so that future flash/unlock attempts require another data reset.

All RAM not already overwritten should be reset during the fastboot flashing unlock process. This measure prevents attacks that read leftover RAM contents from the previous boot. Similarly, unlocked devices should clear RAM at every boot if this does not create an unacceptable delay, but should leave the region used for the kernel's ramoops.

Devices intended for retail should be shipped in the locked state (and with get_unlock_ability returning "0"). This is to ensure an attacker cannot compromise the device by installing their own system or boot image.

Properties

The ro.oem_unlock_supported property should be set at build time based on whether the device supports flashing unlock. ro.oem_unlock_supported should be set to "0" if flashing unlock is not supported on the device or "1" if flashing unlock is supported.

If the device supports flashing unlock (i.e. ro.oem_unlock_supported = 1), then the bootloader should indicate the lock status by setting the kernel command line variable androidboot.flash.locked (or the /firmware/android/flash.locked DT property) to "1" if locked or "0" if unlocked.

Note: For devices that support dm-verity, you can instead use ro.boot.verifiedbootstate to set the value of ro.boot.flash.locked where the value is "0" i.e. unlocked if the verified boot state is orange.

Flashing lock/unlock_critical

The device should support locking and unlocking of critical sections. Those critical sections are defined as whatever is needed to boot the device into the bootloader. This might include fuses, virtual partitions for a sensor hub, first-stage bootloader, and more.

Locking of critical sections is defined as preventing any code (kernel, recovery image, OTA code, etc.) running on the device from deliberately modifying any critical section. This implies that OTAs should fail to update critical sections if the device is in lock critical state. Transitioning from locked to unlocked state should require a physical interaction with the device.

The physical interaction is similar to what fastboot flashing unlock would cause: the user would have to press some physical buttons on the device. The design should not allow programmatically transitioning from lock critical to unlock critical without physical interaction. Devices should ship in the unlock critical state.

Designation of critical partitions/data

Any partitions or data needed for the device to run, need to be either:

  • Re-flashable - either re-buildable, provided, or extractable via some fastboot oem command
  • fully-protected (i.e. considered critical per the previous section)

This includes per-device factory-specific settings, serial numbers, calibration data, etc.

Off-mode charging

If a device supports "off-mode charging" or otherwise autoboots into a special mode when power is applied, fastboot oem off-mode-charge 0 should bypass these special modes and boot as if the user had pressed the power button.

Bootloader for Trusty

Trusty is Google's implementation of a Trusted Execution Environment (TEE) OS that runs alongside Android. This is the specification for devices using ARM TrustzoneTM technology to provide a TEE.

If Trusty is used as the secure OS solution on your ARM device, the bootloader should be implemented as described within the following sections.

Initialization

In order to load and initialize the Trusty OS (TOS), a bootloader should:

  • Set up and configure all available RAM
  • Initialize at least one serial port
  • Verify signature of TOS image
  • Load TOS into RAM (execution from flash or TCM is not supported)
  • Jump to the first instruction in the TOS image after setting up the state and registers as described in the next section

Calling into TOS image

The following state should be configured at entry:

  • MMU turned off
  • Data cache flushed and turned off (instruction cache can be on or off)
  • All interrupts (IRQs and FIQs) disabled
  • CPU in SVC mode on ARM v7 and EL3 on ARM v8
  • Registers in the following state:
    • r0/x0: size of memory allocated to TOS.
    • r1/x1: physical address of a contiguous block of memory that contains platform-specific boot parameters. The layout of this block is platform specific.
    • r2/x2: size of the above block of memory.
    • r14/x30: return address to jump to (in non-secure mode) after TOS initializes.

Note: r0-r3/x0-x3 also serve as scratch registers to TOS. Do not expect their values to be preserved upon return.

On a 64-bit platform:

  • Only w0-w2 are used for parameters, so x0-x2 should contain only 32-bit values.
  • x30 can contain a 64-bit value.
  • The value in x0 when added to the base address of TOS entry-point should result in a 32-bit value. The same applies to the size in register x2 when added to the address of boot parameter block in x1.

Return from TOS

TOS will return to the bootloader in non-secure mode (SCR.NS set to "1") when it is done initializing so that the bootloader may continue loading the primary operating system (e.g., Android).