1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2021-2022, ARM Limited. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <stdbool.h> 9*91f16700Schasinglulu #include <stdint.h> 10*91f16700Schasinglulu #include <lib/spinlock.h> 11*91f16700Schasinglulu #include <plat/common/plat_trng.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu /* 14*91f16700Schasinglulu * # Entropy pool 15*91f16700Schasinglulu * Note that the TRNG Firmware interface can request up to 192 bits of entropy 16*91f16700Schasinglulu * in a single call or three 64bit words per call. We have 4 words in the pool 17*91f16700Schasinglulu * so that when we have 1-63 bits in the pool, and we have a request for 18*91f16700Schasinglulu * 192 bits of entropy, we don't have to throw out the leftover 1-63 bits of 19*91f16700Schasinglulu * entropy. 20*91f16700Schasinglulu */ 21*91f16700Schasinglulu #define WORDS_IN_POOL (4) 22*91f16700Schasinglulu static uint64_t entropy[WORDS_IN_POOL]; 23*91f16700Schasinglulu /* index in bits of the first bit of usable entropy */ 24*91f16700Schasinglulu static uint32_t entropy_bit_index; 25*91f16700Schasinglulu /* then number of valid bits in the entropy pool */ 26*91f16700Schasinglulu static uint32_t entropy_bit_size; 27*91f16700Schasinglulu 28*91f16700Schasinglulu static spinlock_t trng_pool_lock; 29*91f16700Schasinglulu 30*91f16700Schasinglulu #define BITS_PER_WORD (sizeof(entropy[0]) * 8) 31*91f16700Schasinglulu #define BITS_IN_POOL (WORDS_IN_POOL * BITS_PER_WORD) 32*91f16700Schasinglulu #define ENTROPY_MIN_WORD (entropy_bit_index / BITS_PER_WORD) 33*91f16700Schasinglulu #define ENTROPY_FREE_BIT (entropy_bit_size + entropy_bit_index) 34*91f16700Schasinglulu #define _ENTROPY_FREE_WORD (ENTROPY_FREE_BIT / BITS_PER_WORD) 35*91f16700Schasinglulu #define ENTROPY_FREE_INDEX (_ENTROPY_FREE_WORD % WORDS_IN_POOL) 36*91f16700Schasinglulu /* ENTROPY_WORD_INDEX(0) includes leftover bits in the lower bits */ 37*91f16700Schasinglulu #define ENTROPY_WORD_INDEX(i) ((ENTROPY_MIN_WORD + i) % WORDS_IN_POOL) 38*91f16700Schasinglulu 39*91f16700Schasinglulu /* 40*91f16700Schasinglulu * Fill the entropy pool until we have at least as many bits as requested. 41*91f16700Schasinglulu * Returns true after filling the pool, and false if the entropy source is out 42*91f16700Schasinglulu * of entropy and the pool could not be filled. 43*91f16700Schasinglulu * Assumes locks are taken. 44*91f16700Schasinglulu */ 45*91f16700Schasinglulu static bool trng_fill_entropy(uint32_t nbits) 46*91f16700Schasinglulu { 47*91f16700Schasinglulu while (nbits > entropy_bit_size) { 48*91f16700Schasinglulu bool valid = plat_get_entropy(&entropy[ENTROPY_FREE_INDEX]); 49*91f16700Schasinglulu 50*91f16700Schasinglulu if (valid) { 51*91f16700Schasinglulu entropy_bit_size += BITS_PER_WORD; 52*91f16700Schasinglulu assert(entropy_bit_size <= BITS_IN_POOL); 53*91f16700Schasinglulu } else { 54*91f16700Schasinglulu return false; 55*91f16700Schasinglulu } 56*91f16700Schasinglulu } 57*91f16700Schasinglulu return true; 58*91f16700Schasinglulu } 59*91f16700Schasinglulu 60*91f16700Schasinglulu /* 61*91f16700Schasinglulu * Pack entropy into the out buffer, filling and taking locks as needed. 62*91f16700Schasinglulu * Returns true on success, false on failure. 63*91f16700Schasinglulu * 64*91f16700Schasinglulu * Note: out must have enough space for nbits of entropy 65*91f16700Schasinglulu */ 66*91f16700Schasinglulu bool trng_pack_entropy(uint32_t nbits, uint64_t *out) 67*91f16700Schasinglulu { 68*91f16700Schasinglulu bool ret = true; 69*91f16700Schasinglulu uint32_t bits_to_discard = nbits; 70*91f16700Schasinglulu spin_lock(&trng_pool_lock); 71*91f16700Schasinglulu 72*91f16700Schasinglulu if (!trng_fill_entropy(nbits)) { 73*91f16700Schasinglulu ret = false; 74*91f16700Schasinglulu goto out; 75*91f16700Schasinglulu } 76*91f16700Schasinglulu 77*91f16700Schasinglulu const unsigned int rshift = entropy_bit_index % BITS_PER_WORD; 78*91f16700Schasinglulu const unsigned int lshift = BITS_PER_WORD - rshift; 79*91f16700Schasinglulu const int to_fill = ((nbits + BITS_PER_WORD - 1) / BITS_PER_WORD); 80*91f16700Schasinglulu int word_i; 81*91f16700Schasinglulu 82*91f16700Schasinglulu for (word_i = 0; word_i < to_fill; word_i++) { 83*91f16700Schasinglulu /* 84*91f16700Schasinglulu * Repack the entropy from the pool into the passed in out 85*91f16700Schasinglulu * buffer. This takes lesser bits from the valid upper bits 86*91f16700Schasinglulu * of word_i and more bits from the lower bits of (word_i + 1). 87*91f16700Schasinglulu * 88*91f16700Schasinglulu * I found the following diagram useful. note: `e` represents 89*91f16700Schasinglulu * valid entropy, ` ` represents invalid bits (not entropy) and 90*91f16700Schasinglulu * `x` represents valid entropy that must not end up in the 91*91f16700Schasinglulu * packed word. 92*91f16700Schasinglulu * 93*91f16700Schasinglulu * |---------entropy pool----------| 94*91f16700Schasinglulu * C var |--(word_i + 1)-|----word_i-----| 95*91f16700Schasinglulu * bit idx |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| 96*91f16700Schasinglulu * [x,x,e,e,e,e,e,e|e,e, , , , , , ] 97*91f16700Schasinglulu * | [e,e,e,e,e,e,e,e] | 98*91f16700Schasinglulu * | |--out[word_i]--| | 99*91f16700Schasinglulu * lshift|---| |--rshift---| 100*91f16700Schasinglulu * 101*91f16700Schasinglulu * ==== Which is implemented as ==== 102*91f16700Schasinglulu * 103*91f16700Schasinglulu * |---------entropy pool----------| 104*91f16700Schasinglulu * C var |--(word_i + 1)-|----word_i-----| 105*91f16700Schasinglulu * bit idx |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| 106*91f16700Schasinglulu * [x,x,e,e,e,e,e,e|e,e, , , , , , ] 107*91f16700Schasinglulu * C expr << lshift >> rshift 108*91f16700Schasinglulu * bit idx 5 4 3 2 1 0 7 6 109*91f16700Schasinglulu * [e,e,e,e,e,e,0,0|0,0,0,0,0,0,e,e] 110*91f16700Schasinglulu * ==== bit-wise or ==== 111*91f16700Schasinglulu * 5 4 3 2 1 0 7 6 112*91f16700Schasinglulu * [e,e,e,e,e,e,e,e] 113*91f16700Schasinglulu */ 114*91f16700Schasinglulu out[word_i] |= entropy[ENTROPY_WORD_INDEX(word_i)] >> rshift; 115*91f16700Schasinglulu 116*91f16700Schasinglulu /** 117*91f16700Schasinglulu * Discarding the used/packed entropy bits from the respective 118*91f16700Schasinglulu * words, (word_i) and (word_i+1) as applicable. 119*91f16700Schasinglulu * In each iteration of the loop, we pack 64bits of entropy to 120*91f16700Schasinglulu * the output buffer. The bits are picked linearly starting from 121*91f16700Schasinglulu * 1st word (entropy[0]) till 4th word (entropy[3]) and then 122*91f16700Schasinglulu * rolls back (entropy[0]). Discarding of bits is managed 123*91f16700Schasinglulu * similarly. 124*91f16700Schasinglulu * 125*91f16700Schasinglulu * The following diagram illustrates the logic: 126*91f16700Schasinglulu * 127*91f16700Schasinglulu * |---------entropy pool----------| 128*91f16700Schasinglulu * C var |--(word_i + 1)-|----word_i-----| 129*91f16700Schasinglulu * bit idx |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| 130*91f16700Schasinglulu * [e,e,e,e,e,e,e,e|e,e,0,0,0,0,0,0] 131*91f16700Schasinglulu * | [e,e,e,e,e,e,e,e] | 132*91f16700Schasinglulu * | |--out[word_i]--| | 133*91f16700Schasinglulu * lshift|---| |--rshift---| 134*91f16700Schasinglulu * |e,e|0,0,0,0,0,0,0,0|0,0,0,0,0,0| 135*91f16700Schasinglulu * |<== || ==>| 136*91f16700Schasinglulu * bits_to_discard (from these bytes) 137*91f16700Schasinglulu * 138*91f16700Schasinglulu * variable(bits_to_discard): Tracks the amount of bits to be 139*91f16700Schasinglulu * discarded and is updated accordingly in each iteration. 140*91f16700Schasinglulu * 141*91f16700Schasinglulu * It monitors these packed bits from respective word_i and 142*91f16700Schasinglulu * word_i+1 and overwrites them with zeros accordingly. 143*91f16700Schasinglulu * It discards linearly from the lowest index and moves upwards 144*91f16700Schasinglulu * until bits_to_discard variable becomes zero. 145*91f16700Schasinglulu * 146*91f16700Schasinglulu * In the above diagram,for example, we pack 2bytes(7th and 6th 147*91f16700Schasinglulu * from word_i) and 6bytes(0th till 5th from word_i+1), combine 148*91f16700Schasinglulu * and pack them as 64bit to output buffer out[i]. 149*91f16700Schasinglulu * Depending on the number of bits requested, we discard the 150*91f16700Schasinglulu * bits from these packed bytes by overwriting them with zeros. 151*91f16700Schasinglulu */ 152*91f16700Schasinglulu 153*91f16700Schasinglulu /* 154*91f16700Schasinglulu * If the bits to be discarded is lesser than the amount of bits 155*91f16700Schasinglulu * copied to the output buffer from word_i, we discard that much 156*91f16700Schasinglulu * amount of bits only. 157*91f16700Schasinglulu */ 158*91f16700Schasinglulu if (bits_to_discard < (BITS_PER_WORD - rshift)) { 159*91f16700Schasinglulu entropy[ENTROPY_WORD_INDEX(word_i)] &= 160*91f16700Schasinglulu (~0ULL << ((bits_to_discard+rshift) % BITS_PER_WORD)); 161*91f16700Schasinglulu bits_to_discard = 0; 162*91f16700Schasinglulu } else { 163*91f16700Schasinglulu /* 164*91f16700Schasinglulu * If the bits to be discarded is more than the amount of valid 165*91f16700Schasinglulu * upper bits from word_i, which has been copied to the output 166*91f16700Schasinglulu * buffer, we just set the entire word_i to 0, as the lower bits 167*91f16700Schasinglulu * will be already zeros from previous operations, and the 168*91f16700Schasinglulu * bits_to_discard is updated precisely. 169*91f16700Schasinglulu */ 170*91f16700Schasinglulu entropy[ENTROPY_WORD_INDEX(word_i)] = 0; 171*91f16700Schasinglulu bits_to_discard -= (BITS_PER_WORD - rshift); 172*91f16700Schasinglulu } 173*91f16700Schasinglulu 174*91f16700Schasinglulu /* 175*91f16700Schasinglulu * Note that a shift of 64 bits is treated as a shift of 0 bits. 176*91f16700Schasinglulu * When the shift amount is the same as the BITS_PER_WORD, we 177*91f16700Schasinglulu * don't want to include the next word of entropy, so we skip 178*91f16700Schasinglulu * the `|=` operation. 179*91f16700Schasinglulu */ 180*91f16700Schasinglulu if (lshift != BITS_PER_WORD) { 181*91f16700Schasinglulu out[word_i] |= entropy[ENTROPY_WORD_INDEX(word_i + 1)] 182*91f16700Schasinglulu << lshift; 183*91f16700Schasinglulu /** 184*91f16700Schasinglulu * Discarding the remaining packed bits from upperword 185*91f16700Schasinglulu * (word[i+1]) which was copied to output buffer by 186*91f16700Schasinglulu * overwriting with zeros. 187*91f16700Schasinglulu * 188*91f16700Schasinglulu * If the remaining bits to be discarded is lesser than 189*91f16700Schasinglulu * the amount of bits from [word_i+1], which has been 190*91f16700Schasinglulu * copied to the output buffer, we overwrite that much 191*91f16700Schasinglulu * amount of bits only. 192*91f16700Schasinglulu */ 193*91f16700Schasinglulu if (bits_to_discard < (BITS_PER_WORD - lshift)) { 194*91f16700Schasinglulu entropy[ENTROPY_WORD_INDEX(word_i+1)] &= 195*91f16700Schasinglulu (~0ULL << ((bits_to_discard) % BITS_PER_WORD)); 196*91f16700Schasinglulu bits_to_discard = 0; 197*91f16700Schasinglulu } else { 198*91f16700Schasinglulu /* 199*91f16700Schasinglulu * If bits to discard is more than the bits from word_i+1 200*91f16700Schasinglulu * which got packed into the output, then we discard all 201*91f16700Schasinglulu * those copied bits. 202*91f16700Schasinglulu * 203*91f16700Schasinglulu * Note: we cannot set the entire word_i+1 to 0, as 204*91f16700Schasinglulu * there are still some unused valid entropy bits at the 205*91f16700Schasinglulu * upper end for future use. 206*91f16700Schasinglulu */ 207*91f16700Schasinglulu entropy[ENTROPY_WORD_INDEX(word_i+1)] &= 208*91f16700Schasinglulu (~0ULL << ((BITS_PER_WORD - lshift) % BITS_PER_WORD)); 209*91f16700Schasinglulu bits_to_discard -= (BITS_PER_WORD - lshift); 210*91f16700Schasinglulu } 211*91f16700Schasinglulu 212*91f16700Schasinglulu } 213*91f16700Schasinglulu } 214*91f16700Schasinglulu const uint64_t mask = ~0ULL >> (BITS_PER_WORD - (nbits % BITS_PER_WORD)); 215*91f16700Schasinglulu 216*91f16700Schasinglulu out[to_fill - 1] &= mask; 217*91f16700Schasinglulu 218*91f16700Schasinglulu entropy_bit_index = (entropy_bit_index + nbits) % BITS_IN_POOL; 219*91f16700Schasinglulu entropy_bit_size -= nbits; 220*91f16700Schasinglulu 221*91f16700Schasinglulu out: 222*91f16700Schasinglulu spin_unlock(&trng_pool_lock); 223*91f16700Schasinglulu 224*91f16700Schasinglulu return ret; 225*91f16700Schasinglulu } 226*91f16700Schasinglulu 227*91f16700Schasinglulu void trng_entropy_pool_setup(void) 228*91f16700Schasinglulu { 229*91f16700Schasinglulu int i; 230*91f16700Schasinglulu 231*91f16700Schasinglulu for (i = 0; i < WORDS_IN_POOL; i++) { 232*91f16700Schasinglulu entropy[i] = 0; 233*91f16700Schasinglulu } 234*91f16700Schasinglulu entropy_bit_index = 0; 235*91f16700Schasinglulu entropy_bit_size = 0; 236*91f16700Schasinglulu } 237