trng_entropy_pool.c 7.8 KB

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