1 // SPDX-License-Identifier: BSD-2-Clause 2 /** 3 * Copyright 2017-2021, 2024 NXP 4 * 5 * Brief CAAM Random Number Generator manager. 6 * Implementation of RNG functions. 7 */ 8 #include <atomic.h> 9 #include <caam_common.h> 10 #include <caam_hal_rng.h> 11 #include <caam_jr.h> 12 #include <caam_rng.h> 13 #include <caam_utils_mem.h> 14 #include <caam_utils_status.h> 15 #include <crypto/crypto.h> 16 #include <kernel/panic.h> 17 #include <mm/core_memprot.h> 18 #include <rng_support.h> 19 #include <tee/cache.h> 20 #include <tee/tee_cryp_utl.h> 21 #include <string.h> 22 23 /* 24 * Define the number of descriptor entry to generate random data 25 */ 26 #define RNG_GEN_DESC_ENTRIES 5 27 28 /* 29 * RNG module private data 30 */ 31 struct rng_privdata { 32 vaddr_t baseaddr; /* RNG base address */ 33 bool instantiated; /* RNG instantiated */ 34 bool pr_enabled; /* RNG prediction resistance */ 35 }; 36 37 static struct rng_privdata *rng_privdata; 38 39 /* Allocate and initialize module private data */ 40 static enum caam_status do_allocate(void) 41 { 42 /* Allocate the Module resources */ 43 rng_privdata = caam_calloc(sizeof(*rng_privdata)); 44 if (!rng_privdata) { 45 RNG_TRACE("Private Data allocation error"); 46 return CAAM_OUT_MEMORY; 47 } 48 49 rng_privdata->instantiated = false; 50 51 return CAAM_NO_ERROR; 52 } 53 54 /* Free module private data */ 55 static void do_free(void) 56 { 57 caam_free(rng_privdata); 58 rng_privdata = NULL; 59 } 60 61 #ifdef CFG_NXP_CAAM_RNG_DRV 62 /* 63 * Return the requested random data 64 * 65 * @buf [out] data buffer 66 * @len number of bytes to returns 67 */ 68 static TEE_Result do_rng_read(uint8_t *buf, size_t len) 69 { 70 TEE_Result ret = TEE_ERROR_GENERIC; 71 uint32_t *desc = NULL; 72 uint32_t op = RNG_GEN_DATA; 73 void *rng_data = NULL; 74 paddr_t paddr = 0; 75 struct caam_jobctx jobctx = { }; 76 77 if (!rng_privdata) { 78 RNG_TRACE("RNG Driver not initialized"); 79 return TEE_ERROR_BAD_STATE; 80 } 81 82 if (!rng_privdata->instantiated) { 83 RNG_TRACE("RNG Driver not initialized"); 84 return TEE_ERROR_BAD_STATE; 85 } 86 87 rng_data = caam_calloc_align(len); 88 if (!rng_data) { 89 RNG_TRACE("RNG buffer allocation failed"); 90 return TEE_ERROR_OUT_OF_MEMORY; 91 } 92 93 /* Ensure that data buffer is visible from the HW */ 94 cache_operation(TEE_CACHEFLUSH, rng_data, len); 95 96 /* Convert the buffer virtual address to physical address */ 97 paddr = virt_to_phys(rng_data); 98 if (!paddr) { 99 RNG_TRACE("Virtual/Physical conversion failed"); 100 goto exit; 101 } 102 103 desc = caam_calloc_desc(RNG_GEN_DESC_ENTRIES); 104 if (!desc) { 105 RNG_TRACE("Descriptor allocation failed"); 106 ret = TEE_ERROR_OUT_OF_MEMORY; 107 goto exit; 108 } 109 110 if (IS_ENABLED(CFG_CAAM_RNG_RUNTIME_PR) && rng_privdata->pr_enabled) 111 op |= ALGO_RNG_PR; 112 113 caam_desc_init(desc); 114 caam_desc_add_word(desc, DESC_HEADER(0)); 115 caam_desc_add_word(desc, op); 116 caam_desc_add_word(desc, FIFO_ST(CLASS_NO, RNG_TO_MEM, len)); 117 caam_desc_add_ptr(desc, paddr); 118 119 jobctx.desc = desc; 120 RNG_DUMPDESC(desc); 121 122 if (!caam_jr_enqueue(&jobctx, NULL)) { 123 cache_operation(TEE_CACHEINVALIDATE, rng_data, len); 124 memcpy(buf, rng_data, len); 125 ret = TEE_SUCCESS; 126 } else { 127 RNG_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status); 128 ret = job_status_to_tee_result(jobctx.status); 129 } 130 131 exit: 132 caam_free(rng_data); 133 caam_free_desc(&desc); 134 return ret; 135 } 136 #endif /* CFG_NXP_CAAM_RNG_DRV */ 137 138 /* 139 * Prepares the instantiation descriptor 140 * 141 * @nb_sh Number of the State Handle 142 * @sh_status State Handles status 143 * @desc Reference to the descriptor 144 * @desc [out] Descriptor filled 145 */ 146 static void prepare_inst_desc(uint32_t nb_sh, uint32_t sh_status, 147 uint32_t *desc) 148 { 149 bool key_loaded = false; 150 unsigned int sh_idx = 0; 151 unsigned int nb_max_sh = nb_sh; 152 153 /* Read the SH and secure key status */ 154 key_loaded = caam_hal_rng_key_loaded(rng_privdata->baseaddr); 155 RNG_TRACE("RNG SH Status 0x%08" PRIx32 " - Key Status %" PRId8, 156 sh_status, key_loaded); 157 158 while (sh_status & BIT(sh_idx)) 159 sh_idx++; 160 161 RNG_TRACE("Instantiation start at SH%" PRIu32 " (%" PRIu32 ")", sh_idx, 162 nb_max_sh); 163 164 /* Don't set the descriptor header now */ 165 caam_desc_init(desc); 166 caam_desc_add_word(desc, DESC_HEADER(0)); 167 /* First State Handle to instantiate */ 168 caam_desc_add_word(desc, RNG_SH_INST(sh_idx)); 169 170 /* Next State Handles */ 171 for (sh_idx++; sh_idx < nb_max_sh; sh_idx++) { 172 if (!(sh_status & BIT(sh_idx))) { 173 /* 174 * If there is more SH to instantiate, add a wait loop 175 * followed by a reset of the done status to execute 176 * next command 177 */ 178 caam_desc_add_word(desc, 179 JUMP_C1_LOCAL(ALL_COND_TRUE, 180 JMP_COND(NONE), 1)); 181 caam_desc_add_word(desc, 182 LD_NOCLASS_IMM(REG_CLEAR_WRITTEN, 183 sizeof(uint32_t))); 184 caam_desc_add_word(desc, 0x1); 185 caam_desc_add_word(desc, RNG_SH_INST(sh_idx)); 186 } 187 } 188 189 /* Load the Key if needed */ 190 if (!key_loaded) { 191 /* 192 * Add a wait loop while previous operation not completed, 193 * followed by a register clear before executing next command 194 */ 195 caam_desc_add_word(desc, JUMP_C1_LOCAL(ALL_COND_TRUE, 196 JMP_COND(NONE), 1)); 197 caam_desc_add_word(desc, LD_NOCLASS_IMM(REG_CLEAR_WRITTEN, 198 sizeof(uint32_t))); 199 caam_desc_add_word(desc, 0x1); 200 caam_desc_add_word(desc, RNG_GEN_SECKEYS); 201 } 202 203 RNG_DUMPDESC(desc); 204 } 205 206 enum caam_status caam_rng_instantiation(void) 207 { 208 enum caam_status retstatus = CAAM_FAILURE; 209 struct caam_jobctx jobctx = {}; 210 uint32_t *desc = NULL; 211 uint32_t sh_status = 0; 212 uint32_t nb_sh = 0; 213 uint32_t sh_mask = 0; 214 uint32_t inc_delay = 0; 215 216 RNG_TRACE("RNG Instantation"); 217 218 /* Check if RNG is already instantiated */ 219 retstatus = caam_hal_rng_instantiated(rng_privdata->baseaddr); 220 221 /* RNG is already instantiated or an error occurred */ 222 if (retstatus != CAAM_NOT_INIT) 223 goto end_inst; 224 225 /* 226 * RNG needs to be instantiated. Allocate and prepare the 227 * Job Descriptor 228 */ 229 230 /* Calculate the State Handles bit mask */ 231 nb_sh = caam_hal_rng_get_nb_sh(rng_privdata->baseaddr); 232 sh_mask = GENMASK_32(nb_sh - 1, 0); 233 234 /* 235 * The maximum size of the descriptor is: 236 * |----------------------| 237 * | Header | = 1 238 * |----------------------| 239 * | First instantation | = 1 240 * |----------------------|------------------------- 241 * | wait complete | = 1 242 * |----------------------| 243 * | Clear done status | Repeat (nb_sh - 1) 244 * | | = 2 245 * |----------------------| 246 * | next SH instantation | = 1 247 * |----------------------|------------------------- 248 * | wait complete | = 1 249 * |----------------------| 250 * | Clear done status | = 2 251 * | | 252 * |----------------------| 253 * | Generate Secure Keys | = 1 254 * |----------------------| 255 * | Pad with a 0 | = 1 256 */ 257 desc = caam_calloc_desc(2 + (nb_sh - 1) * 4 + 4 + 1); 258 if (!desc) { 259 RNG_TRACE("Descriptor Allocation error"); 260 retstatus = CAAM_OUT_MEMORY; 261 goto end_inst; 262 } 263 264 jobctx.desc = desc; 265 266 do { 267 /* Check if all State Handles are instantiated */ 268 sh_status = caam_hal_rng_get_sh_status(rng_privdata->baseaddr); 269 if ((sh_status & sh_mask) == sh_mask) { 270 RNG_TRACE("RNG All SH are instantiated (0x%08" PRIx32 271 ")", 272 sh_status); 273 retstatus = CAAM_NO_ERROR; 274 goto end_inst; 275 } 276 277 if (sh_status == 0) { 278 retstatus = caam_hal_rng_kick(rng_privdata->baseaddr, 279 inc_delay); 280 RNG_TRACE("RNG Kick (inc=%" PRIu32 ") ret 0x%08x", 281 inc_delay, retstatus); 282 if (retstatus != CAAM_NO_ERROR) { 283 retstatus = CAAM_FAILURE; 284 goto end_inst; 285 } 286 inc_delay += 200; 287 } 288 289 prepare_inst_desc(nb_sh, sh_status, desc); 290 291 retstatus = caam_jr_enqueue(&jobctx, NULL); 292 RNG_TRACE("RNG Job returned 0x%08x", retstatus); 293 294 if (retstatus != CAAM_NO_ERROR && 295 retstatus != CAAM_JOB_STATUS) 296 goto end_inst; 297 298 if (retstatus == CAAM_JOB_STATUS) { 299 RNG_TRACE("RNG Job status 0x%08" PRIx32, jobctx.status); 300 if ((JRSTA_SRC_GET(jobctx.status) != JRSTA_SRC(CCB)) || 301 (JRSTA_CCB_GET_ERR(jobctx.status) != 302 (JRSTA_CCB_CHAID_RNG | JRSTA_CCB_ERRID_HW))) 303 retstatus = CAAM_FAILURE; 304 else 305 retstatus = CAAM_NO_ERROR; 306 } 307 } while (retstatus == CAAM_NO_ERROR); 308 309 end_inst: 310 if (retstatus == CAAM_NO_ERROR) { 311 rng_privdata->instantiated = true; 312 rng_privdata->pr_enabled = 313 caam_hal_rng_pr_enabled(rng_privdata->baseaddr) & 314 IS_ENABLED(CFG_CAAM_RNG_RUNTIME_PR); 315 316 RNG_TRACE("RNG prediction resistance is %sabled", 317 rng_privdata->pr_enabled ? "en" : "dis"); 318 } 319 320 caam_free_desc(&desc); 321 322 RNG_TRACE("RNG Instantiation return 0x%08x", retstatus); 323 324 return retstatus; 325 } 326 327 enum caam_status caam_rng_init(vaddr_t ctrl_addr) 328 { 329 enum caam_status retstatus = CAAM_FAILURE; 330 331 RNG_TRACE("Initialization"); 332 retstatus = do_allocate(); 333 if (retstatus == CAAM_NO_ERROR) { 334 rng_privdata->baseaddr = ctrl_addr; 335 retstatus = caam_rng_instantiation(); 336 } 337 338 if (retstatus != CAAM_NO_ERROR) 339 do_free(); 340 341 return retstatus; 342 } 343 344 #ifdef CFG_NXP_CAAM_RNG_DRV 345 #ifdef CFG_WITH_SOFTWARE_PRNG 346 void plat_rng_init(void) 347 { 348 TEE_Result res = TEE_SUCCESS; 349 uint8_t buf[64] = { }; 350 351 res = do_rng_read(buf, sizeof(buf)); 352 if (res) { 353 EMSG("Failed to read RNG: %#" PRIx32, res); 354 panic(); 355 } 356 357 res = crypto_rng_init(buf, sizeof(buf)); 358 if (res) { 359 EMSG("Failed to initialize RNG: %#" PRIx32, res); 360 panic(); 361 } 362 363 RNG_TRACE("PRNG seeded from CAAM"); 364 } 365 #else /* !CFG_WITH_SOFTWARE_PRNG */ 366 TEE_Result hw_get_random_bytes(void *buf, size_t blen) 367 { 368 if (!buf) 369 return TEE_ERROR_BAD_PARAMETERS; 370 371 return do_rng_read(buf, blen); 372 } 373 374 void plat_rng_init(void) 375 { 376 } 377 #endif /* CFG_WITH_SOFTWARE_PRNG */ 378 #endif /* CFG_NXP_CAAM_RNG_DRV */ 379