17dfb9911SJimmy Brisson /* 2*0b22e591SJayanth Dodderi Chidanand * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved. 37dfb9911SJimmy Brisson * 47dfb9911SJimmy Brisson * SPDX-License-Identifier: BSD-3-Clause 57dfb9911SJimmy Brisson */ 67dfb9911SJimmy Brisson 77dfb9911SJimmy Brisson #include <assert.h> 87dfb9911SJimmy Brisson #include <stdbool.h> 97dfb9911SJimmy Brisson #include <stdint.h> 107dfb9911SJimmy Brisson 117dfb9911SJimmy Brisson #include <arch_features.h> 127dfb9911SJimmy Brisson #include <lib/smccc.h> 137dfb9911SJimmy Brisson #include <services/trng_svc.h> 147dfb9911SJimmy Brisson #include <smccc_helpers.h> 157dfb9911SJimmy Brisson 167dfb9911SJimmy Brisson #include <plat/common/plat_trng.h> 177dfb9911SJimmy Brisson 187dfb9911SJimmy Brisson #include "trng_entropy_pool.h" 197dfb9911SJimmy Brisson 207dfb9911SJimmy Brisson static const uuid_t uuid_null; 217dfb9911SJimmy Brisson 227dfb9911SJimmy Brisson /* handle the RND call in SMC 32 bit mode */ 237dfb9911SJimmy Brisson static uintptr_t trng_rnd32(uint32_t nbits, void *handle) 247dfb9911SJimmy Brisson { 257dfb9911SJimmy Brisson uint32_t mask = ~0U; 26*0b22e591SJayanth Dodderi Chidanand uint64_t ent[2] = {0}; 277dfb9911SJimmy Brisson 28*0b22e591SJayanth Dodderi Chidanand if (nbits == 0U || nbits > TRNG_RND32_ENTROPY_MAXBITS) { 297dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 307dfb9911SJimmy Brisson } 317dfb9911SJimmy Brisson 327dfb9911SJimmy Brisson if (!trng_pack_entropy(nbits, &ent[0])) { 337dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_NO_ENTROPY); 347dfb9911SJimmy Brisson } 357dfb9911SJimmy Brisson 367dfb9911SJimmy Brisson if ((nbits % 32U) != 0U) { 377dfb9911SJimmy Brisson mask >>= 32U - (nbits % 32U); 387dfb9911SJimmy Brisson } 397dfb9911SJimmy Brisson 407dfb9911SJimmy Brisson switch ((nbits - 1U) / 32U) { 417dfb9911SJimmy Brisson case 0: 427dfb9911SJimmy Brisson SMC_RET4(handle, TRNG_E_SUCCESS, 0, 0, ent[0] & mask); 437dfb9911SJimmy Brisson break; /* unreachable */ 447dfb9911SJimmy Brisson case 1: 457dfb9911SJimmy Brisson SMC_RET4(handle, TRNG_E_SUCCESS, 0, (ent[0] >> 32) & mask, 467dfb9911SJimmy Brisson ent[0] & 0xFFFFFFFF); 477dfb9911SJimmy Brisson break; /* unreachable */ 487dfb9911SJimmy Brisson case 2: 497dfb9911SJimmy Brisson SMC_RET4(handle, TRNG_E_SUCCESS, ent[1] & mask, 507dfb9911SJimmy Brisson (ent[0] >> 32) & 0xFFFFFFFF, ent[0] & 0xFFFFFFFF); 517dfb9911SJimmy Brisson break; /* unreachable */ 527dfb9911SJimmy Brisson default: 537dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 547dfb9911SJimmy Brisson break; /* unreachable */ 557dfb9911SJimmy Brisson } 567dfb9911SJimmy Brisson } 577dfb9911SJimmy Brisson 587dfb9911SJimmy Brisson /* handle the RND call in SMC 64 bit mode */ 597dfb9911SJimmy Brisson static uintptr_t trng_rnd64(uint32_t nbits, void *handle) 607dfb9911SJimmy Brisson { 617dfb9911SJimmy Brisson uint64_t mask = ~0ULL; 62*0b22e591SJayanth Dodderi Chidanand uint64_t ent[3] = {0}; 637dfb9911SJimmy Brisson 64*0b22e591SJayanth Dodderi Chidanand if (nbits == 0U || nbits > TRNG_RND64_ENTROPY_MAXBITS) { 657dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 667dfb9911SJimmy Brisson } 677dfb9911SJimmy Brisson 687dfb9911SJimmy Brisson if (!trng_pack_entropy(nbits, &ent[0])) { 697dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_NO_ENTROPY); 707dfb9911SJimmy Brisson } 717dfb9911SJimmy Brisson 727dfb9911SJimmy Brisson /* Mask off higher bits if only part of register requested */ 737dfb9911SJimmy Brisson if ((nbits % 64U) != 0U) { 747dfb9911SJimmy Brisson mask >>= 64U - (nbits % 64U); 757dfb9911SJimmy Brisson } 767dfb9911SJimmy Brisson 777dfb9911SJimmy Brisson switch ((nbits - 1U) / 64U) { 787dfb9911SJimmy Brisson case 0: 797dfb9911SJimmy Brisson SMC_RET4(handle, TRNG_E_SUCCESS, 0, 0, ent[0] & mask); 807dfb9911SJimmy Brisson break; /* unreachable */ 817dfb9911SJimmy Brisson case 1: 827dfb9911SJimmy Brisson SMC_RET4(handle, TRNG_E_SUCCESS, 0, ent[1] & mask, ent[0]); 837dfb9911SJimmy Brisson break; /* unreachable */ 847dfb9911SJimmy Brisson case 2: 857dfb9911SJimmy Brisson SMC_RET4(handle, TRNG_E_SUCCESS, ent[2] & mask, ent[1], ent[0]); 867dfb9911SJimmy Brisson break; /* unreachable */ 877dfb9911SJimmy Brisson default: 887dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_INVALID_PARAMS); 897dfb9911SJimmy Brisson break; /* unreachable */ 907dfb9911SJimmy Brisson } 917dfb9911SJimmy Brisson } 927dfb9911SJimmy Brisson 937dfb9911SJimmy Brisson void trng_setup(void) 947dfb9911SJimmy Brisson { 957dfb9911SJimmy Brisson trng_entropy_pool_setup(); 967dfb9911SJimmy Brisson plat_entropy_setup(); 977dfb9911SJimmy Brisson } 987dfb9911SJimmy Brisson 997dfb9911SJimmy Brisson /* Predicate indicating that a function id is part of TRNG */ 1007dfb9911SJimmy Brisson bool is_trng_fid(uint32_t smc_fid) 1017dfb9911SJimmy Brisson { 1027dfb9911SJimmy Brisson return ((smc_fid == ARM_TRNG_VERSION) || 1037dfb9911SJimmy Brisson (smc_fid == ARM_TRNG_FEATURES) || 1047dfb9911SJimmy Brisson (smc_fid == ARM_TRNG_GET_UUID) || 1057dfb9911SJimmy Brisson (smc_fid == ARM_TRNG_RND32) || 1067dfb9911SJimmy Brisson (smc_fid == ARM_TRNG_RND64)); 1077dfb9911SJimmy Brisson } 1087dfb9911SJimmy Brisson 1097dfb9911SJimmy Brisson uintptr_t trng_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, 1107dfb9911SJimmy Brisson u_register_t x3, u_register_t x4, void *cookie, 1117dfb9911SJimmy Brisson void *handle, u_register_t flags) 1127dfb9911SJimmy Brisson { 1137dfb9911SJimmy Brisson if (!memcmp(&plat_trng_uuid, &uuid_null, sizeof(uuid_t))) { 1147dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_NOT_IMPLEMENTED); 1157dfb9911SJimmy Brisson } 1167dfb9911SJimmy Brisson 1177dfb9911SJimmy Brisson switch (smc_fid) { 1187dfb9911SJimmy Brisson case ARM_TRNG_VERSION: 1197dfb9911SJimmy Brisson SMC_RET1(handle, MAKE_SMCCC_VERSION( 120*0b22e591SJayanth Dodderi Chidanand TRNG_VERSION_MAJOR, TRNG_VERSION_MINOR)); 1217dfb9911SJimmy Brisson break; /* unreachable */ 122*0b22e591SJayanth Dodderi Chidanand 1237dfb9911SJimmy Brisson case ARM_TRNG_FEATURES: 1247dfb9911SJimmy Brisson if (is_trng_fid((uint32_t)x1)) { 1257dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_SUCCESS); 1267dfb9911SJimmy Brisson } else { 1277dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_NOT_SUPPORTED); 1287dfb9911SJimmy Brisson } 1297dfb9911SJimmy Brisson break; /* unreachable */ 130*0b22e591SJayanth Dodderi Chidanand 1317dfb9911SJimmy Brisson case ARM_TRNG_GET_UUID: 1327dfb9911SJimmy Brisson SMC_UUID_RET(handle, plat_trng_uuid); 1337dfb9911SJimmy Brisson break; /* unreachable */ 134*0b22e591SJayanth Dodderi Chidanand 1357dfb9911SJimmy Brisson case ARM_TRNG_RND32: 1367dfb9911SJimmy Brisson return trng_rnd32((uint32_t)x1, handle); 137*0b22e591SJayanth Dodderi Chidanand 1387dfb9911SJimmy Brisson case ARM_TRNG_RND64: 1397dfb9911SJimmy Brisson return trng_rnd64((uint32_t)x1, handle); 140*0b22e591SJayanth Dodderi Chidanand 1417dfb9911SJimmy Brisson default: 142*0b22e591SJayanth Dodderi Chidanand WARN("Unimplemented TRNG Service Call: 0x%x\n", smc_fid); 1437dfb9911SJimmy Brisson SMC_RET1(handle, TRNG_E_NOT_IMPLEMENTED); 1447dfb9911SJimmy Brisson break; /* unreachable */ 1457dfb9911SJimmy Brisson } 1467dfb9911SJimmy Brisson } 147