1 /* 2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arm_acle.h> 8 #include <assert.h> 9 #include <stdbool.h> 10 #include <stdint.h> 11 #include <string.h> 12 13 #include <lib/mmio.h> 14 #include <lib/utils_def.h> 15 #include <platform_def.h> 16 17 #include "juno_decl.h" 18 19 #define NSAMPLE_CLOCKS 1 /* min 1 cycle, max 231 cycles */ 20 #define NRETRIES 5 21 22 /* initialised to false */ 23 static bool juno_trng_initialized; 24 25 static bool output_valid(void) 26 { 27 int i; 28 29 for (i = 0; i < NRETRIES; i++) { 30 uint32_t val; 31 32 val = mmio_read_32(TRNG_BASE + TRNG_STATUS); 33 if (val & 1U) 34 return true; 35 } 36 return false; /* No output data available. */ 37 } 38 39 static uint32_t crc_value = ~0U; 40 41 /* 42 * This function fills `buf` with 8 bytes of entropy. 43 * It uses the Trusted Entropy Source peripheral on Juno. 44 * Returns 'true' when the buffer has been filled with entropy 45 * successfully, or 'false' otherwise. 46 */ 47 bool juno_getentropy(uint64_t *buf) 48 { 49 uint64_t ret; 50 51 assert(buf); 52 assert(!check_uptr_overflow((uintptr_t)buf, sizeof(*buf))); 53 54 if (!juno_trng_initialized) { 55 /* Disable interrupt mode. */ 56 mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0); 57 /* Program TRNG to sample for `NSAMPLE_CLOCKS`. */ 58 mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS); 59 /* Abort any potentially pending sampling. */ 60 mmio_write_32(TRNG_BASE + TRNG_CONTROL, 2); 61 /* Reset TRNG outputs. */ 62 mmio_write_32(TRNG_BASE + TRNG_STATUS, 1); 63 64 juno_trng_initialized = true; 65 } 66 67 if (!output_valid()) { 68 /* Start TRNG. */ 69 mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1); 70 71 if (!output_valid()) 72 return false; 73 } 74 75 /* CRC each two 32-bit registers together, combine the pairs */ 76 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 0)); 77 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 4)); 78 ret = (uint64_t)crc_value << 32; 79 80 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 8)); 81 crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 12)); 82 *buf = ret | crc_value; 83 84 /* Acknowledge current cycle, clear output registers. */ 85 mmio_write_32(TRNG_BASE + TRNG_STATUS, 1); 86 /* Trigger next TRNG cycle. */ 87 mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1); 88 89 return true; 90 } 91