Merge pull request #1483 from antonio-nino-diaz-arm/an/rpi3-psci

rpi3: PSCI and Linux boot improvements
This commit is contained in:
danh-arm 2018-07-19 15:37:54 +01:00 committed by GitHub
commit 992a353613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 293 additions and 110 deletions

View File

@ -7,8 +7,7 @@ Trusted Firmware-A for Raspberry Pi 3
.. contents::
The `Raspberry Pi 3`_ is an inexpensive single-board computer that contains four
Arm Cortex-A53 cores, which makes it possible to have a port of Trusted
Firmware-A (TF-A).
Arm Cortex-A53 cores.
The following instructions explain how to use this port of the TF-A with the
default distribution of `Raspbian`_ because that's the distribution officially
@ -66,7 +65,7 @@ Placement of images
The file ``armstub8.bin`` contains BL1 and the FIP. It is needed to add padding
between them so that the addresses they are loaded to match the ones specified
when compiling TF-A.
when compiling TF-A. This is done automatically by the build system.
The device tree block is loaded by the VideoCore loader from an appropriate
file, but we can specify the address it is loaded to in ``config.txt``.
@ -108,13 +107,13 @@ secure platform!
| ... |
| |
0x01000000 +-----------------+
| Kernel |
| DTB | (Loaded by the VideoCore)
+-----------------+
| |
| ... |
| |
0x02000000 +-----------------+
| DTB |
| Kernel | (Loaded by the VideoCore)
+-----------------+
| |
| ... |
@ -123,9 +122,9 @@ secure platform!
| Secure SRAM | BL2, BL31
0x10100000 +-----------------+
| Secure DRAM | BL32 (Secure payload)
0x10C00000 +-----------------+
| Non-secure DRAM | BL33
0x11000000 +-----------------+
| Non-secure DRAM | BL33
+-----------------+
| |
| ... |
| |
@ -133,10 +132,10 @@ secure platform!
| I/O |
0x40000000 +-----------------+
The area between **0x10000000** and **0x11000000** has to be protected so that
the kernel doesn't use it. That is done by adding ``memmap=16M$256M`` to the
command line passed to the kernel. See the `Setup SD card`_ instructions to see
how to do it.
The area between **0x10000000** and **0x11000000** has to be manually protected
so that the kernel doesn't use it. That is done by adding ``memmap=16M$256M`` to
the command line passed to the kernel. See the `Setup SD card`_ instructions to
see how to do it.
The last 16 MiB of DRAM can only be accessed by the VideoCore, that has
different mappings than the Arm cores in which the I/O addresses don't overlap
@ -159,14 +158,24 @@ The `Linux kernel tree`_ has instructions on how to jump to the Linux kernel
in ``Documentation/arm/Booting`` and ``Documentation/arm64/booting.txt``. The
bootstrap should take care of this.
This port support a direct boot of the Linux kernel from the firmware (as a BL33
image). Alternatively, U-Boot or other bootloaders may be used.
Secondary cores
~~~~~~~~~~~~~~~
This port of the Trusted Firmware-A supports ``PSCI_CPU_ON``,
`PSCI_SYSTEM_RESET`` and ``PSCI_SYSTEM_OFF``. The last one doesn't really turn
the system off, it simply reboots it and asks the VideoCore firmware to keep it
in a low power mode permanently.
The kernel used by `Raspbian`_ doesn't have support for PSCI, so it is needed to
use mailboxes to trap the secondary cores until they are ready to jump to the
kernel. This mailbox is located at a different address in the AArch32 default
kernel than in the AArch64 kernel.
Kernels with PSCI support can use the PSCI calls instead for a cleaner boot.
Also, this port of TF-A has another Trusted Mailbox in Shared BL RAM. During
cold boot, all secondary cores wait in a loop until they are given given an
address to jump to in this Mailbox (``bl31_warm_entrypoint``).
@ -187,46 +196,38 @@ To boot a AArch32 kernel, both AArch64 and AArch32 toolchains are required. The
AArch32 toolchain is needed for the AArch32 bootstrap needed to load a 32-bit
kernel.
First, clone and compile `Raspberry Pi 3 TF-A bootstrap`_. Choose the one
needed for the architecture of your kernel.
Then compile TF-A. For a AArch32 kernel, use the following command line:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
RPI3_BL33_IN_AARCH32=1 \
BL33=../rpi3-arm-tf-bootstrap/aarch32/el2-bootstrap.bin
For a AArch64 kernel, use this other command line:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
BL33=../rpi3-arm-tf-bootstrap/aarch64/el2-bootstrap.bin
The build system concatenates BL1 and the FIP so that the addresses match the
ones in the memory map. The resulting file is ``armstub8.bin``, located in the
build folder (e.g. ``build/rpi3/debug/armstub8.bin``). Now, follow the
instructions in `Setup SD card`_.
build folder (e.g. ``build/rpi3/debug/armstub8.bin``). To know how to use this
file, follow the instructions in `Setup SD card`_.
The following build options are supported:
- ``PRELOADED_BL33_BASE``: Specially useful because the file ``kernel8.img`` can
be loaded anywhere by modifying the file ``config.txt``. It doesn't have to
contain a kernel, it could have any arbitrary payload.
- ``RESET_TO_BL31``: Set to 1 by default. If using a 32-bit kernel like
`Raspbian`_, the space used by BL1 can overwritten by the kernel when it is
being loaded. Even when using a AArch64 kernel the region used by
BL1 isn't protected and the kernel could overwrite it. The space used by BL31
is reserved by the command line passed to the kernel.
- ``RPI3_BL33_IN_AARCH32``: This port can load a AArch64 or AArch32 BL33 image.
By default this option is 0, which means that TF-A will jump to BL33 in EL2
in AArch64 mode. If set to 1, it will jump to BL33 in Hypervisor in AArch32
mode.
- ``PRELOADED_BL33_BASE``: Used to specify the address of a BL33 binary that has
been preloaded by any other system than using the firmware. ``BL33`` isn't
needed in the build command line if this option is used. Specially useful
because the file ``kernel8.img`` can be loaded anywhere by modifying the file
``config.txt``. It doesn't have to contain a kernel, it could have any
arbitrary payload.
- ``RPI3_DIRECT_LINUX_BOOT``: Disabled by default. Set to 1 to enable the direct
boot of the Linux kernel from the firmware. Option ``RPI3_PRELOADED_DTB_BASE``
is mandatory when the direct Linux kernel boot is used. Options
``PRELOADED_BL33_BASE`` will most likely be needed as well because it is
unlikely that the kernel image will fit in the space reserved for BL33 images.
This option can be combined with ``RPI3_BL33_IN_AARCH32`` in order to boot a
32-bit kernel. The only thing this option does is to set the arguments in
registers x0-x3 or r0-r2 as expected by the kernel.
- ``RPI3_PRELOADED_DTB_BASE``: Auxiliary build option needed when using
``RPI3_DIRECT_LINUX_BOOT=1``. This option allows to specify the location of a
DTB in memory.
- ``BL32``: This port can load and run OP-TEE. The OP-TEE image is optional.
Please use the code from `here <https://github.com/OP-TEE/optee_os>`__.
Build the Trusted Firmware with option ``BL32=tee-header_v2.bin
@ -239,15 +240,16 @@ The following build options are supported:
This will unfortunately reduce the performance of the USB driver. It is needed
when using Raspbian, for example.
- ``TRUSTED_BOARD_BOOT``: This port supports TBB. Set this option
``TRUSTED_BOARD_BOOT=1`` to enable it. In order to use TBB, you might
want to set ``GENERATE_COT=1`` to let the contents of the FIP automatically
signed by the build process. The ROT key will be generated and output to
``rot_key.pem`` in the build directory. It is able to set ROT_KEY to
your own key in PEM format.
Also in order to build, you need to clone mbedtls from
`here <https://github.com/ARMmbed/mbedtls>`__.
And set MBEDTLS_DIR to mbedtls source directory.
- ``TRUSTED_BOARD_BOOT``: This port supports TBB. Set this option to 1 to enable
it. In order to use TBB, you might want to set ``GENERATE_COT=1`` to let the
contents of the FIP automatically signed by the build process. The ROT key
will be generated and output to ``rot_key.pem`` in the build directory. It is
able to set ROT_KEY to your own key in PEM format. Also in order to build,
you need to clone mbed TLS from `here <https://github.com/ARMmbed/mbedtls>`__.
``MBEDTLS_DIR`` must point at the mbed TLS source directory.
- ``ENABLE_STACK_PROTECTOR``: Disabled by default. It uses the hardware RNG of
the board.
The following is not currently supported:
@ -257,13 +259,65 @@ The following is not currently supported:
address by changing the file ``armstub8.bin``, so there's no point in using
TF-A in this case.
- ``LOAD_IMAGE_V2=0``: Only version 2 is supported.
- ``MULTI_CONSOLE_API=0``: The multi console API must be enabled. Note that the
crash console uses the internal 16550 driver functions directly in order to be
able to print error messages during early crashes before setting up the
multi console API.
Building the firmware for kernels that don't support PSCI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the case for the 32-bit image of Raspbian, for example. 64-bit kernels
always support PSCI, but they may not know that the system understands PSCI due
to an incorrect DTB file.
First, clone and compile the 32-bit version of the `Raspberry Pi 3 TF-A
bootstrap`_. Choose the one needed for the architecture of your kernel.
Then compile TF-A. For a 32-bit kernel, use the following command line:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
RPI3_BL33_IN_AARCH32=1 \
BL33=../rpi3-arm-tf-bootstrap/aarch32/el2-bootstrap.bin
For a 64-bit kernel, use this other command line:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
BL33=../rpi3-arm-tf-bootstrap/aarch64/el2-bootstrap.bin
However, enabling PSCI support in a 64-bit kernel is really easy. In the
repository `Raspberry Pi 3 TF-A bootstrap`_ there is a patch that can be applied
to the Linux kernel tree maintained by the Raspberry Pi foundation. It modifes
the DTS to tell the kernel to use PSCI. Once this patch is applied, follow the
instructions in `AArch64 kernel build instructions`_ to get a working 64-bit
kernel image and supporting files.
Building the firmware for kernels that support PSCI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For a 64-bit kernel:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
PRELOADED_BL33_BASE=0x02000000 \
RPI3_PRELOADED_DTB_BASE=0x01000000 \
RPI3_DIRECT_LINUX_BOOT=1
For a 32-bit kernel:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
PRELOADED_BL33_BASE=0x02000000 \
RPI3_PRELOADED_DTB_BASE=0x01000000 \
RPI3_DIRECT_LINUX_BOOT=1 \
RPI3_BL33_IN_AARCH32=1
AArch64 kernel build instructions
---------------------------------
@ -280,7 +334,7 @@ allows the user to run 64-bit binaries in addition to 32-bit binaries.
.. code:: shell
git clone --depth=1 -b rpi-4.14.y https://github.com/raspberrypi/linux
git clone --depth=1 -b rpi-4.18.y https://github.com/raspberrypi/linux
cd linux
2. Configure and compile the kernel. Adapt the number after ``-j`` so that it is
@ -300,6 +354,7 @@ allows the user to run 64-bit binaries in addition to 32-bit binaries.
cp arch/arm64/boot/Image /path/to/boot/kernel8.img
cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb /path/to/boot/
cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dtb /path/to/boot/
4. Install the kernel modules. Replace the path by the corresponding path to the
filesystem partition of the SD card on your computer.
@ -343,8 +398,8 @@ untouched). They have been tested with the image available in 2018-03-13.
::
enable_uart=1
kernel_address=0x01000000
device_tree_address=0x02000000
kernel_address=0x02000000
device_tree_address=0x01000000
If you connect a serial cable to the Mini UART and your computer, and connect
to it (for example, with ``screen /dev/ttyUSB0 115200``) you should see some

View File

@ -175,9 +175,5 @@ func plat_reset_handler
mov w1, #0x80000000
str wzr, [x0, #RPI3_INTC_CONTROL_OFFSET]
str w1, [x0, #RPI3_INTC_PRESCALER_OFFSET]
/* wire mailbox 3 to the FIQ line */
mov w1, RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ
str w1, [x0, #RPI3_INTC_MBOX_CONTROL_OFFSET]
ret
endfunc plat_reset_handler

View File

@ -70,17 +70,17 @@
#define PLAT_RPI3_FIP_BASE ULL(0x00020000)
#define PLAT_RPI3_FIP_MAX_SIZE ULL(0x001E0000)
/* We have 16M of memory reserved at at 256M */
/* We have 16M of memory reserved starting at 256M */
#define SEC_SRAM_BASE ULL(0x10000000)
#define SEC_SRAM_SIZE ULL(0x00100000)
#define SEC_DRAM0_BASE ULL(0x10100000)
#define SEC_DRAM0_SIZE ULL(0x00B00000)
#define NS_DRAM0_BASE ULL(0x10C00000)
#define NS_DRAM0_SIZE ULL(0x00400000)
#define SEC_DRAM0_SIZE ULL(0x00F00000)
/* End of reserved memory */
#define NS_DRAM0_BASE ULL(0x11000000)
#define NS_DRAM0_SIZE ULL(0x01000000)
/*
* BL33 entrypoint.
*/
@ -117,9 +117,11 @@
*/
#define PLAT_RPI3_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE
/* The secure entry point to be used on warm reset by all CPUs. */
#define PLAT_RPI3_TM_ENTRYPOINT PLAT_RPI3_TRUSTED_MAILBOX_BASE
#define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8)
/* Hold entries for each CPU. */
#define PLAT_RPI3_TM_HOLD_BASE (PLAT_RPI3_TM_ENTRYPOINT + \
PLAT_RPI3_TM_ENTRYPOINT_SIZE)
#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE ULL(8)

View File

@ -90,8 +90,11 @@ WORKAROUND_CVE_2017_5715 := 0
# Disable the PSCI platform compatibility layer by default
ENABLE_PLAT_COMPAT := 0
# Enable reset to BL31 by default
RESET_TO_BL31 := 1
# Disable stack protector by default
ENABLE_STACK_PROTECTOR := 0
# Reset to BL31 isn't supported
RESET_TO_BL31 := 0
# Have different sections for code and rodata
SEPARATE_CODE_AND_RODATA := 1
@ -111,6 +114,9 @@ MULTI_CONSOLE_API := 1
# BL33 images are in AArch64 by default
RPI3_BL33_IN_AARCH32 := 0
# Assume that BL33 isn't the Linux kernel by default
RPI3_DIRECT_LINUX_BOOT := 0
# BL32 location
RPI3_BL32_RAM_LOCATION := tdram
ifeq (${RPI3_BL32_RAM_LOCATION}, tsram)
@ -126,9 +132,17 @@ endif
$(eval $(call add_define,RPI3_BL32_RAM_LOCATION_ID))
$(eval $(call add_define,RPI3_BL33_IN_AARCH32))
$(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT))
$(eval $(call add_define,RPI3_PRELOADED_DTB_BASE))
# Verify build config
# -------------------
#
ifneq (${RPI3_DIRECT_LINUX_BOOT}, 0)
ifndef RPI3_PRELOADED_DTB_BASE
$(error Error: RPI3_PRELOADED_DTB_BASE needed if RPI3_DIRECT_LINUX_BOOT=1)
endif
endif
ifneq (${LOAD_IMAGE_V2}, 1)
$(error Error: rpi3 needs LOAD_IMAGE_V2=1)
@ -138,10 +152,19 @@ ifneq (${MULTI_CONSOLE_API}, 1)
$(error Error: rpi3 needs MULTI_CONSOLE_API=1)
endif
ifneq (${RESET_TO_BL31}, 0)
$(error Error: rpi3 needs RESET_TO_BL31=0)
endif
ifeq (${ARCH},aarch32)
$(error Error: AArch32 not supported on rpi3)
endif
ifneq ($(ENABLE_STACK_PROTECTOR), 0)
PLAT_BL_COMMON_SOURCES += plat/rpi3/rpi3_rng.c \
plat/rpi3/rpi3_stack_protector.c
endif
ifeq (${SPD},opteed)
BL2_SOURCES += \
lib/optee/optee_utils.c

View File

@ -59,39 +59,6 @@ void bl31_early_platform_setup(void *from_bl2,
/* Initialize the console to provide early debug support */
rpi3_console_init();
#if RESET_TO_BL31
/* There are no parameters from BL2 if BL31 is a reset vector */
assert(from_bl2 == NULL);
assert(plat_params_from_bl2 == NULL);
#ifdef BL32_BASE
/* Populate entry point information for BL32 */
SET_PARAM_HEAD(&bl32_image_ep_info,
PARAM_EP,
VERSION_1,
0);
SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
bl32_image_ep_info.pc = BL32_BASE;
bl32_image_ep_info.spsr = rpi3_get_spsr_for_bl32_entry();
#endif /* BL32_BASE */
/* Populate entry point information for BL33 */
SET_PARAM_HEAD(&bl33_image_ep_info,
PARAM_EP,
VERSION_1,
0);
/*
* Tell BL31 where the non-trusted software image
* is located and the entry state information
*/
bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
bl33_image_ep_info.spsr = rpi3_get_spsr_for_bl33_entry();
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
#else /* RESET_TO_BL31 */
/*
* In debug builds, we pass a special value in 'plat_params_from_bl2'
* to verify platform parameters from BL2 to BL31.
@ -130,7 +97,33 @@ void bl31_early_platform_setup(void *from_bl2,
panic();
}
#endif /* RESET_TO_BL31 */
#if RPI3_DIRECT_LINUX_BOOT
# if RPI3_BL33_IN_AARCH32
/*
* According to the file ``Documentation/arm/Booting`` of the Linux
* kernel tree, Linux expects:
* r0 = 0
* r1 = machine type number, optional in DT-only platforms (~0 if so)
* r2 = Physical address of the device tree blob
*/
VERBOSE("rpi3: Preparing to boot 32-bit Linux kernel\n");
bl33_image_ep_info.args.arg0 = 0U;
bl33_image_ep_info.args.arg1 = ~0U;
bl33_image_ep_info.args.arg2 = (u_register_t) RPI3_PRELOADED_DTB_BASE;
# else
/*
* According to the file ``Documentation/arm64/booting.txt`` of the
* Linux kernel tree, Linux expects the physical address of the device
* tree blob (DTB) in x0, while x1-x3 are reserved for future use and
* must be 0.
*/
VERBOSE("rpi3: Preparing to boot 64-bit Linux kernel\n");
bl33_image_ep_info.args.arg0 = (u_register_t) RPI3_PRELOADED_DTB_BASE;
bl33_image_ep_info.args.arg1 = 0ULL;
bl33_image_ep_info.args.arg2 = 0ULL;
bl33_image_ep_info.args.arg3 = 0ULL;
# endif /* RPI3_BL33_IN_AARCH32 */
#endif /* RPI3_DIRECT_LINUX_BOOT */
}
void bl31_plat_arch_setup(void)
@ -148,12 +141,10 @@ void bl31_plat_arch_setup(void)
void bl31_platform_setup(void)
{
#if RESET_TO_BL31
/*
* Do initial security configuration to allow DRAM/device access
* (if earlier BL has not already done so).
*/
#endif /* RESET_TO_BL31 */
return;
}

View File

@ -58,6 +58,24 @@
*/
#define RPI3_PM_RSTS_WRCFG_HALT U(0x00000555)
/*
* Hardware random number generator.
*/
#define RPI3_IO_RNG_OFFSET ULL(0x00104000)
#define RPI3_RNG_BASE (RPI3_IO_BASE + RPI3_IO_RNG_OFFSET)
#define RPI3_RNG_CTRL_OFFSET ULL(0x00000000)
#define RPI3_RNG_STATUS_OFFSET ULL(0x00000004)
#define RPI3_RNG_DATA_OFFSET ULL(0x00000008)
#define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010)
/* Enable/disable RNG */
#define RPI3_RNG_CTRL_ENABLE U(0x1)
#define RPI3_RNG_CTRL_DISABLE U(0x0)
/* Number of currently available words */
#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24)
#define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF)
/* Value to mask interrupts caused by the RNG */
#define RPI3_RNG_INT_MASK_DISABLE U(0x1)
/*
* Serial port (called 'Mini UART' in the BCM docucmentation).
*/

View File

@ -15,11 +15,6 @@
#include "rpi3_hw.h"
/*
* The secure entry point to be used on warm reset.
*/
static uintptr_t secure_entrypoint;
/* Make composite power state parameter till power level 0 */
#if PSCI_EXTENDED_STATE_ID
@ -220,10 +215,9 @@ static const plat_psci_ops_t plat_rpi3_psci_pm_ops = {
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
uintptr_t *mailbox = (void *)PLAT_RPI3_TRUSTED_MAILBOX_BASE;
uintptr_t *entrypoint = (void *) PLAT_RPI3_TM_ENTRYPOINT;
*mailbox = sec_entrypoint;
secure_entrypoint = (uintptr_t)sec_entrypoint;
*entrypoint = sec_entrypoint;
*psci_ops = &plat_rpi3_psci_pm_ops;
return 0;

View File

@ -33,6 +33,9 @@ uint32_t rpi3_get_spsr_for_bl33_entry(void);
/* IO storage utility functions */
void plat_rpi3_io_setup(void);
/* Hardware RNG functions */
void rpi3_rng_read(void *buf, size_t len);
/* VideoCore firmware commands */
int rpi3_vc_hardware_get_board_revision(uint32_t *revision);

74
plat/rpi3/rpi3_rng.c Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <mmio.h>
#include <string.h>
#include "rpi3_hw.h"
/* Initial amount of values to discard */
#define RNG_WARMUP_COUNT U(0x40000)
static void rpi3_rng_initialize(void)
{
uint32_t int_mask, ctrl;
/* Return if it is already enabled */
ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET);
if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) {
return;
}
/* Mask interrupts */
int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET);
int_mask |= RPI3_RNG_INT_MASK_DISABLE;
mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask);
/* Discard several values when initializing to give it time to warmup */
mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT);
mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET,
RPI3_RNG_CTRL_ENABLE);
}
static uint32_t rpi3_rng_get_word(void)
{
size_t nwords;
do {
/* Get number of available words to read */
nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET)
>> RPI3_RNG_STATUS_NUM_WORDS_SHIFT)
& RPI3_RNG_STATUS_NUM_WORDS_MASK;
} while (nwords == 0U);
return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET);
}
void rpi3_rng_read(void *buf, size_t len)
{
uint32_t data;
size_t left = len;
uint32_t *dst = buf;
assert(buf != NULL);
assert(len != 0U);
assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0);
rpi3_rng_initialize();
while (left >= sizeof(uint32_t)) {
data = rpi3_rng_get_word();
*dst++ = data;
left -= sizeof(uint32_t);
}
if (left > 0U) {
data = rpi3_rng_get_word();
memcpy(dst, &data, left);
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <sys/types.h>
#include <utils.h>
#include "rpi3_private.h"
/* Get 128 bits of entropy and fuse the values together to form the canary. */
#define TRNG_NBYTES 16U
u_register_t plat_get_stack_protector_canary(void)
{
size_t i;
u_register_t buf[TRNG_NBYTES / sizeof(u_register_t)];
u_register_t ret = 0U;
rpi3_rng_read(buf, sizeof(buf));
for (i = 0U; i < ARRAY_SIZE(buf); i++)
ret ^= buf[i];
return ret;
}