1 /* 2 * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stdbool.h> 9 #include <stdint.h> 10 11 #include <arch_features.h> 12 #include <lib/smccc.h> 13 #include <services/trng_svc.h> 14 #include <smccc_helpers.h> 15 16 #include <plat/common/plat_trng.h> 17 18 #include "trng_entropy_pool.h" 19 20 static const uuid_t uuid_null; 21 22 /* handle the RND call in SMC 32 bit mode */ 23 static uintptr_t trng_rnd32(uint32_t nbits, void *handle) 24 { 25 uint32_t mask = ~0U; 26 uint64_t ent[2] = {0}; 27 28 if (nbits == 0U || nbits > TRNG_RND32_ENTROPY_MAXBITS) { 29 SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 30 } 31 32 if (!trng_pack_entropy(nbits, &ent[0])) { 33 SMC_RET1(handle, TRNG_E_NO_ENTROPY); 34 } 35 36 if ((nbits % 32U) != 0U) { 37 mask >>= 32U - (nbits % 32U); 38 } 39 40 switch ((nbits - 1U) / 32U) { 41 case 0: 42 SMC_RET4(handle, TRNG_E_SUCCESS, 0, 0, ent[0] & mask); 43 break; /* unreachable */ 44 case 1: 45 SMC_RET4(handle, TRNG_E_SUCCESS, 0, (ent[0] >> 32) & mask, 46 ent[0] & 0xFFFFFFFF); 47 break; /* unreachable */ 48 case 2: 49 SMC_RET4(handle, TRNG_E_SUCCESS, ent[1] & mask, 50 (ent[0] >> 32) & 0xFFFFFFFF, ent[0] & 0xFFFFFFFF); 51 break; /* unreachable */ 52 default: 53 SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 54 break; /* unreachable */ 55 } 56 } 57 58 /* handle the RND call in SMC 64 bit mode */ 59 static uintptr_t trng_rnd64(uint32_t nbits, void *handle) 60 { 61 uint64_t mask = ~0ULL; 62 uint64_t ent[3] = {0}; 63 64 if (nbits == 0U || nbits > TRNG_RND64_ENTROPY_MAXBITS) { 65 SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 66 } 67 68 if (!trng_pack_entropy(nbits, &ent[0])) { 69 SMC_RET1(handle, TRNG_E_NO_ENTROPY); 70 } 71 72 /* Mask off higher bits if only part of register requested */ 73 if ((nbits % 64U) != 0U) { 74 mask >>= 64U - (nbits % 64U); 75 } 76 77 switch ((nbits - 1U) / 64U) { 78 case 0: 79 SMC_RET4(handle, TRNG_E_SUCCESS, 0, 0, ent[0] & mask); 80 break; /* unreachable */ 81 case 1: 82 SMC_RET4(handle, TRNG_E_SUCCESS, 0, ent[1] & mask, ent[0]); 83 break; /* unreachable */ 84 case 2: 85 SMC_RET4(handle, TRNG_E_SUCCESS, ent[2] & mask, ent[1], ent[0]); 86 break; /* unreachable */ 87 default: 88 SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 89 break; /* unreachable */ 90 } 91 } 92 93 void trng_setup(void) 94 { 95 trng_entropy_pool_setup(); 96 plat_entropy_setup(); 97 } 98 99 /* Predicate indicating that a function id is part of TRNG */ 100 bool is_trng_fid(uint32_t smc_fid) 101 { 102 return ((smc_fid == ARM_TRNG_VERSION) || 103 (smc_fid == ARM_TRNG_FEATURES) || 104 (smc_fid == ARM_TRNG_GET_UUID) || 105 (smc_fid == ARM_TRNG_RND32) || 106 (smc_fid == ARM_TRNG_RND64)); 107 } 108 109 uintptr_t trng_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, 110 u_register_t x3, u_register_t x4, void *cookie, 111 void *handle, u_register_t flags) 112 { 113 if (!memcmp(&plat_trng_uuid, &uuid_null, sizeof(uuid_t))) { 114 SMC_RET1(handle, TRNG_E_NOT_IMPLEMENTED); 115 } 116 117 switch (smc_fid) { 118 case ARM_TRNG_VERSION: 119 SMC_RET1(handle, MAKE_SMCCC_VERSION( 120 TRNG_VERSION_MAJOR, TRNG_VERSION_MINOR)); 121 break; /* unreachable */ 122 123 case ARM_TRNG_FEATURES: 124 if (is_trng_fid((uint32_t)x1)) { 125 SMC_RET1(handle, TRNG_E_SUCCESS); 126 } else { 127 SMC_RET1(handle, TRNG_E_NOT_SUPPORTED); 128 } 129 break; /* unreachable */ 130 131 case ARM_TRNG_GET_UUID: 132 SMC_UUID_RET(handle, plat_trng_uuid); 133 break; /* unreachable */ 134 135 case ARM_TRNG_RND32: 136 return trng_rnd32((uint32_t)x1, handle); 137 138 case ARM_TRNG_RND64: 139 return trng_rnd64((uint32_t)x1, handle); 140 141 default: 142 WARN("Unimplemented TRNG Service Call: 0x%x\n", smc_fid); 143 SMC_RET1(handle, TRNG_E_NOT_IMPLEMENTED); 144 break; /* unreachable */ 145 } 146 } 147