1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Software based random number provider for the Kernel Cryptographic 31*0Sstevel@tonic-gate * Framework (KCF). This provider periodically collects unpredictable input 32*0Sstevel@tonic-gate * from external sources and processes it into a pool of entropy (randomness) 33*0Sstevel@tonic-gate * in order to satisfy requests for random bits from kCF. It implements 34*0Sstevel@tonic-gate * software-based mixing, extraction, and generation algorithms. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * A history note: The software-based algorithms in this file used to be 37*0Sstevel@tonic-gate * part of the /dev/random driver. 38*0Sstevel@tonic-gate */ 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #include <sys/types.h> 41*0Sstevel@tonic-gate #include <sys/errno.h> 42*0Sstevel@tonic-gate #include <sys/debug.h> 43*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 44*0Sstevel@tonic-gate #include <vm/hat.h> 45*0Sstevel@tonic-gate #include <sys/systm.h> 46*0Sstevel@tonic-gate #include <sys/memlist.h> 47*0Sstevel@tonic-gate #include <sys/cmn_err.h> 48*0Sstevel@tonic-gate #include <sys/ksynch.h> 49*0Sstevel@tonic-gate #include <sys/random.h> 50*0Sstevel@tonic-gate #include <sys/ddi.h> 51*0Sstevel@tonic-gate #include <sys/mman.h> 52*0Sstevel@tonic-gate #include <sys/sysmacros.h> 53*0Sstevel@tonic-gate #include <sys/mem_config.h> 54*0Sstevel@tonic-gate #include <sys/time.h> 55*0Sstevel@tonic-gate #include <sys/crypto/spi.h> 56*0Sstevel@tonic-gate #include <sys/sha1.h> 57*0Sstevel@tonic-gate #include <sys/sunddi.h> 58*0Sstevel@tonic-gate #include <sys/modctl.h> 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate #define RNDPOOLSIZE 1024 /* Pool size in bytes */ 61*0Sstevel@tonic-gate #define HASHBUFSIZE 64 /* Buffer size used for pool mixing */ 62*0Sstevel@tonic-gate #define MAXMEMBLOCKS 16384 /* Number of memory blocks to scan */ 63*0Sstevel@tonic-gate #define MEMBLOCKSIZE 4096 /* Size of memory block to read */ 64*0Sstevel@tonic-gate #define MINEXTRACTBITS 160 /* Min entropy level for extraction */ 65*0Sstevel@tonic-gate #define TIMEOUT_INTERVAL 5 /* Periodic mixing interval in secs */ 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* Hash-algo generic definitions. For now, they are SHA1's. */ 68*0Sstevel@tonic-gate #define HASHSIZE 20 69*0Sstevel@tonic-gate #define HASH_CTX SHA1_CTX 70*0Sstevel@tonic-gate #define HashInit(ctx) SHA1Init((ctx)) 71*0Sstevel@tonic-gate #define HashUpdate(ctx, p, s) SHA1Update((ctx), (p), (s)) 72*0Sstevel@tonic-gate #define HashFinal(d, ctx) SHA1Final((d), (ctx)) 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate /* Physical memory entropy source */ 75*0Sstevel@tonic-gate typedef struct physmem_entsrc_s { 76*0Sstevel@tonic-gate uint8_t *parity; /* parity bit vector */ 77*0Sstevel@tonic-gate caddr_t pmbuf; /* buffer for memory block */ 78*0Sstevel@tonic-gate uint32_t nblocks; /* number of memory blocks */ 79*0Sstevel@tonic-gate int entperblock; /* entropy bits per block read */ 80*0Sstevel@tonic-gate hrtime_t last_diff; /* previous time to process a block */ 81*0Sstevel@tonic-gate hrtime_t last_delta; /* previous time delta */ 82*0Sstevel@tonic-gate hrtime_t last_delta2; /* previous 2nd order time delta */ 83*0Sstevel@tonic-gate } physmem_entsrc_t; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate static uint32_t srndpool[RNDPOOLSIZE/4]; /* Pool of random bits */ 86*0Sstevel@tonic-gate static uint32_t entropy_bits; /* pool's current amount of entropy */ 87*0Sstevel@tonic-gate static kmutex_t srndpool_lock; /* protects r/w accesses to the pool, */ 88*0Sstevel@tonic-gate /* and the global variables */ 89*0Sstevel@tonic-gate static kcondvar_t srndpool_read_cv; /* serializes poll/read syscalls */ 90*0Sstevel@tonic-gate static int pindex; /* Global index for adding/extracting */ 91*0Sstevel@tonic-gate /* from the pool */ 92*0Sstevel@tonic-gate static uint8_t leftover[HASHSIZE]; /* leftover output */ 93*0Sstevel@tonic-gate static int leftover_bytes; /* leftover length */ 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate static physmem_entsrc_t entsrc; /* Physical mem as an entropy source */ 96*0Sstevel@tonic-gate static timeout_id_t rnd_timeout_id; 97*0Sstevel@tonic-gate static int snum_waiters; 98*0Sstevel@tonic-gate static crypto_kcf_provider_handle_t swrand_prov_handle = NULL; 99*0Sstevel@tonic-gate swrand_stats_t swrand_stats; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate static int physmem_ent_init(physmem_entsrc_t *); 102*0Sstevel@tonic-gate static void physmem_ent_fini(physmem_entsrc_t *); 103*0Sstevel@tonic-gate static void physmem_ent_gen(physmem_entsrc_t *); 104*0Sstevel@tonic-gate static int physmem_parity_update(uint8_t *, uint32_t, int); 105*0Sstevel@tonic-gate static void physmem_count_blocks(); 106*0Sstevel@tonic-gate static void rnd_dr_callback_post_add(void *, pgcnt_t); 107*0Sstevel@tonic-gate static int rnd_dr_callback_pre_del(void *, pgcnt_t); 108*0Sstevel@tonic-gate static void rnd_dr_callback_post_del(void *, pgcnt_t, int); 109*0Sstevel@tonic-gate static void rnd_handler(void *arg); 110*0Sstevel@tonic-gate static void swrand_init(); 111*0Sstevel@tonic-gate static void swrand_schedule_timeout(void); 112*0Sstevel@tonic-gate static int swrand_get_entropy(uint8_t *ptr, size_t len, boolean_t); 113*0Sstevel@tonic-gate static void swrand_add_entropy(uint8_t *ptr, size_t len, uint16_t entropy_est); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate /* Dynamic Reconfiguration related declarations */ 116*0Sstevel@tonic-gate kphysm_setup_vector_t rnd_dr_callback_vec = { 117*0Sstevel@tonic-gate KPHYSM_SETUP_VECTOR_VERSION, 118*0Sstevel@tonic-gate rnd_dr_callback_post_add, 119*0Sstevel@tonic-gate rnd_dr_callback_pre_del, 120*0Sstevel@tonic-gate rnd_dr_callback_post_del 121*0Sstevel@tonic-gate }; 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate extern struct mod_ops mod_cryptoops; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * Module linkage information for the kernel. 127*0Sstevel@tonic-gate */ 128*0Sstevel@tonic-gate static struct modlcrypto modlcrypto = { 129*0Sstevel@tonic-gate &mod_cryptoops, 130*0Sstevel@tonic-gate "Kernel Random number Provider %I%" 131*0Sstevel@tonic-gate }; 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 134*0Sstevel@tonic-gate MODREV_1, 135*0Sstevel@tonic-gate (void *)&modlcrypto, 136*0Sstevel@tonic-gate NULL 137*0Sstevel@tonic-gate }; 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate /* 140*0Sstevel@tonic-gate * CSPI information (entry points, provider info, etc.) 141*0Sstevel@tonic-gate */ 142*0Sstevel@tonic-gate static void swrand_provider_status(crypto_provider_handle_t, uint_t *); 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate static crypto_control_ops_t swrand_control_ops = { 145*0Sstevel@tonic-gate swrand_provider_status 146*0Sstevel@tonic-gate }; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate static int swrand_seed_random(crypto_provider_handle_t, crypto_session_id_t, 149*0Sstevel@tonic-gate uchar_t *, size_t, crypto_req_handle_t); 150*0Sstevel@tonic-gate static int swrand_generate_random(crypto_provider_handle_t, 151*0Sstevel@tonic-gate crypto_session_id_t, uchar_t *, size_t, crypto_req_handle_t); 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate static crypto_random_number_ops_t swrand_random_number_ops = { 154*0Sstevel@tonic-gate swrand_seed_random, 155*0Sstevel@tonic-gate swrand_generate_random 156*0Sstevel@tonic-gate }; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate static crypto_ops_t swrand_crypto_ops = { 159*0Sstevel@tonic-gate &swrand_control_ops, 160*0Sstevel@tonic-gate NULL, 161*0Sstevel@tonic-gate NULL, 162*0Sstevel@tonic-gate NULL, 163*0Sstevel@tonic-gate NULL, 164*0Sstevel@tonic-gate NULL, 165*0Sstevel@tonic-gate NULL, 166*0Sstevel@tonic-gate NULL, 167*0Sstevel@tonic-gate &swrand_random_number_ops, 168*0Sstevel@tonic-gate NULL, 169*0Sstevel@tonic-gate NULL, 170*0Sstevel@tonic-gate NULL, 171*0Sstevel@tonic-gate NULL, 172*0Sstevel@tonic-gate NULL 173*0Sstevel@tonic-gate }; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate static crypto_provider_info_t swrand_prov_info = { 176*0Sstevel@tonic-gate CRYPTO_SPI_VERSION_1, 177*0Sstevel@tonic-gate "Kernel Random Number Provider", 178*0Sstevel@tonic-gate CRYPTO_SW_PROVIDER, 179*0Sstevel@tonic-gate {&modlinkage}, 180*0Sstevel@tonic-gate NULL, 181*0Sstevel@tonic-gate &swrand_crypto_ops, 182*0Sstevel@tonic-gate 0, 183*0Sstevel@tonic-gate NULL 184*0Sstevel@tonic-gate }; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate int 187*0Sstevel@tonic-gate _init(void) 188*0Sstevel@tonic-gate { 189*0Sstevel@tonic-gate int ret; 190*0Sstevel@tonic-gate hrtime_t ts; 191*0Sstevel@tonic-gate time_t now; 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate /* 194*0Sstevel@tonic-gate * Register with KCF. If the registration fails, return error. 195*0Sstevel@tonic-gate */ 196*0Sstevel@tonic-gate if ((ret = crypto_register_provider(&swrand_prov_info, 197*0Sstevel@tonic-gate &swrand_prov_handle)) != CRYPTO_SUCCESS) { 198*0Sstevel@tonic-gate cmn_err(CE_WARN, "swrand : Kernel Random Number Provider " 199*0Sstevel@tonic-gate "disabled for /dev/random use"); 200*0Sstevel@tonic-gate return (EACCES); 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate mutex_init(&srndpool_lock, NULL, MUTEX_DEFAULT, NULL); 204*0Sstevel@tonic-gate cv_init(&srndpool_read_cv, NULL, CV_DEFAULT, NULL); 205*0Sstevel@tonic-gate entropy_bits = 0; 206*0Sstevel@tonic-gate pindex = 0; 207*0Sstevel@tonic-gate snum_waiters = 0; 208*0Sstevel@tonic-gate leftover_bytes = 0; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* 211*0Sstevel@tonic-gate * Initialize the pool using 212*0Sstevel@tonic-gate * . 2 unpredictable times: high resolution time since the boot-time, 213*0Sstevel@tonic-gate * and the current time-of-the day. 214*0Sstevel@tonic-gate * . The initial physical memory state. 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate ts = gethrtime(); 217*0Sstevel@tonic-gate swrand_add_entropy((uint8_t *)&ts, sizeof (ts), 0); 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate (void) drv_getparm(TIME, &now); 220*0Sstevel@tonic-gate swrand_add_entropy((uint8_t *)&now, sizeof (now), 0); 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate ret = kphysm_setup_func_register(&rnd_dr_callback_vec, NULL); 223*0Sstevel@tonic-gate ASSERT(ret == 0); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if (physmem_ent_init(&entsrc) != 0) { 226*0Sstevel@tonic-gate mutex_destroy(&srndpool_lock); 227*0Sstevel@tonic-gate cv_destroy(&srndpool_read_cv); 228*0Sstevel@tonic-gate (void) crypto_unregister_provider(swrand_prov_handle); 229*0Sstevel@tonic-gate return (ENOMEM); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate if ((ret = mod_install(&modlinkage)) != 0) { 233*0Sstevel@tonic-gate mutex_destroy(&srndpool_lock); 234*0Sstevel@tonic-gate cv_destroy(&srndpool_read_cv); 235*0Sstevel@tonic-gate physmem_ent_fini(&entsrc); 236*0Sstevel@tonic-gate (void) crypto_unregister_provider(swrand_prov_handle); 237*0Sstevel@tonic-gate return (ret); 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* Schedule periodic mixing of the pool. */ 241*0Sstevel@tonic-gate mutex_enter(&srndpool_lock); 242*0Sstevel@tonic-gate swrand_schedule_timeout(); 243*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate return (0); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate int 249*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 250*0Sstevel@tonic-gate { 251*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* 255*0Sstevel@tonic-gate * Control entry points. 256*0Sstevel@tonic-gate */ 257*0Sstevel@tonic-gate /* ARGSUSED */ 258*0Sstevel@tonic-gate static void 259*0Sstevel@tonic-gate swrand_provider_status(crypto_provider_handle_t provider, uint_t *status) 260*0Sstevel@tonic-gate { 261*0Sstevel@tonic-gate *status = CRYPTO_PROVIDER_READY; 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate /* 265*0Sstevel@tonic-gate * Random number entry points. 266*0Sstevel@tonic-gate */ 267*0Sstevel@tonic-gate /* ARGSUSED */ 268*0Sstevel@tonic-gate static int 269*0Sstevel@tonic-gate swrand_seed_random(crypto_provider_handle_t provider, crypto_session_id_t sid, 270*0Sstevel@tonic-gate uchar_t *buf, size_t len, crypto_req_handle_t req) 271*0Sstevel@tonic-gate { 272*0Sstevel@tonic-gate /* The entropy estimate is always 0 in this path */ 273*0Sstevel@tonic-gate swrand_add_entropy(buf, len, 0); 274*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* ARGSUSED */ 278*0Sstevel@tonic-gate static int 279*0Sstevel@tonic-gate swrand_generate_random(crypto_provider_handle_t provider, 280*0Sstevel@tonic-gate crypto_session_id_t sid, uchar_t *buf, size_t len, crypto_req_handle_t req) 281*0Sstevel@tonic-gate { 282*0Sstevel@tonic-gate if (crypto_kmflag(req) == KM_NOSLEEP) 283*0Sstevel@tonic-gate (void) swrand_get_entropy(buf, len, B_TRUE); 284*0Sstevel@tonic-gate else 285*0Sstevel@tonic-gate (void) swrand_get_entropy(buf, len, B_FALSE); 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate return (CRYPTO_SUCCESS); 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * Extraction of entropy from the pool. 293*0Sstevel@tonic-gate * 294*0Sstevel@tonic-gate * Returns "len" random bytes in *ptr. 295*0Sstevel@tonic-gate * Try to gather some more entropy by calling physmem_ent_gen() when less than 296*0Sstevel@tonic-gate * MINEXTRACTBITS are present in the pool. 297*0Sstevel@tonic-gate * Will block if not enough entropy was available and the call is blocking. 298*0Sstevel@tonic-gate */ 299*0Sstevel@tonic-gate static int 300*0Sstevel@tonic-gate swrand_get_entropy(uint8_t *ptr, size_t len, boolean_t nonblock) 301*0Sstevel@tonic-gate { 302*0Sstevel@tonic-gate int i, bytes; 303*0Sstevel@tonic-gate HASH_CTX hashctx; 304*0Sstevel@tonic-gate uint8_t digest[HASHSIZE], *pool; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate mutex_enter(&srndpool_lock); 307*0Sstevel@tonic-gate if (leftover_bytes > 0) { 308*0Sstevel@tonic-gate bytes = min(len, leftover_bytes); 309*0Sstevel@tonic-gate bcopy(leftover, ptr, bytes); 310*0Sstevel@tonic-gate len -= bytes; 311*0Sstevel@tonic-gate ptr += bytes; 312*0Sstevel@tonic-gate leftover_bytes -= bytes; 313*0Sstevel@tonic-gate if (leftover_bytes > 0) 314*0Sstevel@tonic-gate ovbcopy(leftover+bytes, leftover, leftover_bytes); 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate while (len > 0) { 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* Check if there is enough entropy */ 320*0Sstevel@tonic-gate while (entropy_bits < MINEXTRACTBITS) { 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate physmem_ent_gen(&entsrc); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate if (entropy_bits < MINEXTRACTBITS && 325*0Sstevel@tonic-gate nonblock == B_TRUE) { 326*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 327*0Sstevel@tonic-gate return (EAGAIN); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (entropy_bits < MINEXTRACTBITS) { 331*0Sstevel@tonic-gate ASSERT(nonblock == B_FALSE); 332*0Sstevel@tonic-gate snum_waiters++; 333*0Sstevel@tonic-gate if (cv_wait_sig(&srndpool_read_cv, 334*0Sstevel@tonic-gate &srndpool_lock) == 0) { 335*0Sstevel@tonic-gate snum_waiters--; 336*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 337*0Sstevel@tonic-gate return (EINTR); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate snum_waiters--; 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* Figure out how many bytes to extract */ 344*0Sstevel@tonic-gate bytes = min(HASHSIZE, len); 345*0Sstevel@tonic-gate bytes = min(bytes, entropy_bits/8); 346*0Sstevel@tonic-gate entropy_bits -= bytes * 8; 347*0Sstevel@tonic-gate BUMP_SWRAND_STATS(ss_entOut, bytes * 8); 348*0Sstevel@tonic-gate swrand_stats.ss_entEst = entropy_bits; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate /* Extract entropy by hashing pool content */ 351*0Sstevel@tonic-gate HashInit(&hashctx); 352*0Sstevel@tonic-gate HashUpdate(&hashctx, (uint8_t *)srndpool, RNDPOOLSIZE); 353*0Sstevel@tonic-gate HashFinal(digest, &hashctx); 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate /* 356*0Sstevel@tonic-gate * Feed the digest back into the pool so next 357*0Sstevel@tonic-gate * extraction produces different result 358*0Sstevel@tonic-gate */ 359*0Sstevel@tonic-gate pool = (uint8_t *)srndpool; 360*0Sstevel@tonic-gate for (i = 0; i < HASHSIZE; i++) { 361*0Sstevel@tonic-gate pool[pindex++] ^= digest[i]; 362*0Sstevel@tonic-gate /* pindex modulo RNDPOOLSIZE */ 363*0Sstevel@tonic-gate pindex &= (RNDPOOLSIZE - 1); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * Hash the digest again before output to obscure 368*0Sstevel@tonic-gate * what was fed back to the pool. 369*0Sstevel@tonic-gate */ 370*0Sstevel@tonic-gate HashInit(&hashctx); 371*0Sstevel@tonic-gate HashUpdate(&hashctx, digest, HASHSIZE); 372*0Sstevel@tonic-gate if (len >= HASHSIZE) 373*0Sstevel@tonic-gate HashFinal(ptr, &hashctx); 374*0Sstevel@tonic-gate else { 375*0Sstevel@tonic-gate HashFinal(digest, &hashctx); 376*0Sstevel@tonic-gate bcopy(digest, ptr, bytes); 377*0Sstevel@tonic-gate leftover_bytes = HASHSIZE - bytes; 378*0Sstevel@tonic-gate bcopy(digest + bytes, leftover, leftover_bytes); 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate len -= bytes; 382*0Sstevel@tonic-gate ptr += bytes; 383*0Sstevel@tonic-gate BUMP_SWRAND_STATS(ss_bytesOut, bytes); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 386*0Sstevel@tonic-gate return (0); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* Write some more user-provided entropy to the pool */ 390*0Sstevel@tonic-gate static void 391*0Sstevel@tonic-gate swrand_add_bytes(uint8_t *ptr, size_t len) 392*0Sstevel@tonic-gate { 393*0Sstevel@tonic-gate uint8_t *pool = (uint8_t *)srndpool; 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&srndpool_lock)); 396*0Sstevel@tonic-gate ASSERT(ptr != NULL && len > 0); 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate BUMP_SWRAND_STATS(ss_bytesIn, len); 399*0Sstevel@tonic-gate while (len--) { 400*0Sstevel@tonic-gate pool[pindex++] ^= *ptr; 401*0Sstevel@tonic-gate ptr++; 402*0Sstevel@tonic-gate pindex &= (RNDPOOLSIZE - 1); 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* Mix the pool */ 407*0Sstevel@tonic-gate static void 408*0Sstevel@tonic-gate swrand_mix_pool(uint16_t entropy_est) 409*0Sstevel@tonic-gate { 410*0Sstevel@tonic-gate int i, j, k, start; 411*0Sstevel@tonic-gate HASH_CTX hashctx; 412*0Sstevel@tonic-gate uint8_t digest[HASHSIZE]; 413*0Sstevel@tonic-gate uint8_t *pool = (uint8_t *)srndpool; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&srndpool_lock)); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate start = 0; 418*0Sstevel@tonic-gate for (i = 0; i < RNDPOOLSIZE/HASHSIZE + 1; i++) { 419*0Sstevel@tonic-gate HashInit(&hashctx); 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate /* Hash a buffer centered on a block in the pool */ 422*0Sstevel@tonic-gate if (start + HASHBUFSIZE <= RNDPOOLSIZE) 423*0Sstevel@tonic-gate HashUpdate(&hashctx, &pool[start], HASHBUFSIZE); 424*0Sstevel@tonic-gate else { 425*0Sstevel@tonic-gate HashUpdate(&hashctx, &pool[start], 426*0Sstevel@tonic-gate RNDPOOLSIZE - start); 427*0Sstevel@tonic-gate HashUpdate(&hashctx, pool, 428*0Sstevel@tonic-gate HASHBUFSIZE - RNDPOOLSIZE + start); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate HashFinal(digest, &hashctx); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate /* XOR the hash result back into the block */ 433*0Sstevel@tonic-gate k = (start + HASHSIZE) & (RNDPOOLSIZE - 1); 434*0Sstevel@tonic-gate for (j = 0; j < HASHSIZE; j++) { 435*0Sstevel@tonic-gate pool[k++] ^= digest[j]; 436*0Sstevel@tonic-gate k &= (RNDPOOLSIZE - 1); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* Slide the hash buffer and repeat with next block */ 440*0Sstevel@tonic-gate start = (start + HASHSIZE) & (RNDPOOLSIZE - 1); 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate entropy_bits += entropy_est; 444*0Sstevel@tonic-gate if (entropy_bits > RNDPOOLSIZE * 8) 445*0Sstevel@tonic-gate entropy_bits = RNDPOOLSIZE * 8; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate swrand_stats.ss_entEst = entropy_bits; 448*0Sstevel@tonic-gate BUMP_SWRAND_STATS(ss_entIn, entropy_est); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate static void 452*0Sstevel@tonic-gate swrand_add_entropy(uint8_t *ptr, size_t len, uint16_t entropy_est) 453*0Sstevel@tonic-gate { 454*0Sstevel@tonic-gate mutex_enter(&srndpool_lock); 455*0Sstevel@tonic-gate swrand_add_bytes(ptr, len); 456*0Sstevel@tonic-gate swrand_mix_pool(entropy_est); 457*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate /* 461*0Sstevel@tonic-gate * The physmem_* routines below generate entropy by reading blocks of 462*0Sstevel@tonic-gate * physical memory. Entropy is gathered in a couple of ways: 463*0Sstevel@tonic-gate * 464*0Sstevel@tonic-gate * - By reading blocks of physical memory and detecting if changes 465*0Sstevel@tonic-gate * occurred in the blocks read. 466*0Sstevel@tonic-gate * 467*0Sstevel@tonic-gate * - By measuring the time it takes to load and hash a block of memory 468*0Sstevel@tonic-gate * and computing the differences in the measured time. 469*0Sstevel@tonic-gate * 470*0Sstevel@tonic-gate * The first method was used in the CryptoRand implementation. Physical 471*0Sstevel@tonic-gate * memory is divided into blocks of fixed size. A block of memory is 472*0Sstevel@tonic-gate * chosen from the possible blocks and hashed to produce a digest. This 473*0Sstevel@tonic-gate * digest is then mixed into the pool. A single bit from the digest is 474*0Sstevel@tonic-gate * used as a parity bit or "checksum" and compared against the previous 475*0Sstevel@tonic-gate * "checksum" computed for the block. If the single-bit checksum has not 476*0Sstevel@tonic-gate * changed, no entropy is credited to the pool. If there is a change, 477*0Sstevel@tonic-gate * then the assumption is that at least one bit in the block has changed. 478*0Sstevel@tonic-gate * The possible locations within the memory block of where the bit change 479*0Sstevel@tonic-gate * occurred is used as a measure of entropy. For example, if a block 480*0Sstevel@tonic-gate * size of 4096 bytes is used, about log_2(4096*8)=15 bits worth of 481*0Sstevel@tonic-gate * entropy is available. Because the single-bit checksum will miss half 482*0Sstevel@tonic-gate * of the changes, the amount of entropy credited to the pool is doubled 483*0Sstevel@tonic-gate * when a change is detected. With a 4096 byte block size, a block 484*0Sstevel@tonic-gate * change will add a total of 30 bits of entropy to the pool. 485*0Sstevel@tonic-gate * 486*0Sstevel@tonic-gate * The second method measures the amount of time it takes to read and 487*0Sstevel@tonic-gate * hash a physical memory block (as described above). The time measured 488*0Sstevel@tonic-gate * can vary depending on system load, scheduling and other factors. 489*0Sstevel@tonic-gate * Differences between consecutive measurements are computed to come up 490*0Sstevel@tonic-gate * with an entropy estimate. The first, second, and third order delta is 491*0Sstevel@tonic-gate * calculated to determine the minimum delta value. The number of bits 492*0Sstevel@tonic-gate * present in this minimum delta value is the entropy estimate. This 493*0Sstevel@tonic-gate * entropy estimation technique using time deltas is similar to that used 494*0Sstevel@tonic-gate * in /dev/random implementations from Linux/BSD. 495*0Sstevel@tonic-gate */ 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate static int 498*0Sstevel@tonic-gate physmem_ent_init(physmem_entsrc_t *entsrc) 499*0Sstevel@tonic-gate { 500*0Sstevel@tonic-gate uint8_t *ptr; 501*0Sstevel@tonic-gate int i; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate bzero(entsrc, sizeof (*entsrc)); 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate /* 506*0Sstevel@tonic-gate * The maximum entropy amount in bits per block of memory read is 507*0Sstevel@tonic-gate * log_2(MEMBLOCKSIZE * 8); 508*0Sstevel@tonic-gate */ 509*0Sstevel@tonic-gate i = MEMBLOCKSIZE << 3; 510*0Sstevel@tonic-gate while (i >>= 1) 511*0Sstevel@tonic-gate entsrc->entperblock++; 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate /* Initialize entsrc->nblocks */ 514*0Sstevel@tonic-gate physmem_count_blocks(); 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if (entsrc->nblocks == 0) { 517*0Sstevel@tonic-gate cmn_err(CE_WARN, "no memory blocks to scan!"); 518*0Sstevel@tonic-gate return (-1); 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* Allocate space for the parity vector and memory page */ 522*0Sstevel@tonic-gate entsrc->parity = kmem_alloc(howmany(entsrc->nblocks, 8), 523*0Sstevel@tonic-gate KM_SLEEP); 524*0Sstevel@tonic-gate entsrc->pmbuf = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate /* Initialize parity vector with bits from the pool */ 528*0Sstevel@tonic-gate i = howmany(entsrc->nblocks, 8); 529*0Sstevel@tonic-gate ptr = entsrc->parity; 530*0Sstevel@tonic-gate while (i > 0) { 531*0Sstevel@tonic-gate if (i > RNDPOOLSIZE) { 532*0Sstevel@tonic-gate bcopy(srndpool, ptr, RNDPOOLSIZE); 533*0Sstevel@tonic-gate mutex_enter(&srndpool_lock); 534*0Sstevel@tonic-gate swrand_mix_pool(0); 535*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 536*0Sstevel@tonic-gate ptr += RNDPOOLSIZE; 537*0Sstevel@tonic-gate i -= RNDPOOLSIZE; 538*0Sstevel@tonic-gate } else { 539*0Sstevel@tonic-gate bcopy(srndpool, ptr, i); 540*0Sstevel@tonic-gate break; 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate /* Generate some entropy to further initialize the pool */ 545*0Sstevel@tonic-gate mutex_enter(&srndpool_lock); 546*0Sstevel@tonic-gate physmem_ent_gen(entsrc); 547*0Sstevel@tonic-gate entropy_bits = 0; 548*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate return (0); 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate static void 554*0Sstevel@tonic-gate physmem_ent_fini(physmem_entsrc_t *entsrc) 555*0Sstevel@tonic-gate { 556*0Sstevel@tonic-gate if (entsrc->pmbuf != NULL) 557*0Sstevel@tonic-gate vmem_free(heap_arena, entsrc->pmbuf, PAGESIZE); 558*0Sstevel@tonic-gate if (entsrc->parity != NULL) 559*0Sstevel@tonic-gate kmem_free(entsrc->parity, howmany(entsrc->nblocks, 8)); 560*0Sstevel@tonic-gate bzero(entsrc, sizeof (*entsrc)); 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate static void 564*0Sstevel@tonic-gate physmem_ent_gen(physmem_entsrc_t *entsrc) 565*0Sstevel@tonic-gate { 566*0Sstevel@tonic-gate struct memlist *pmem; 567*0Sstevel@tonic-gate offset_t offset, poffset; 568*0Sstevel@tonic-gate pfn_t pfn; 569*0Sstevel@tonic-gate int i, nbytes, len, ent = 0; 570*0Sstevel@tonic-gate uint32_t block, oblock; 571*0Sstevel@tonic-gate hrtime_t ts1, ts2, diff, delta, delta2, delta3; 572*0Sstevel@tonic-gate uint8_t digest[HASHSIZE]; 573*0Sstevel@tonic-gate HASH_CTX ctx; 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate /* 576*0Sstevel@tonic-gate * Use each 32-bit quantity in the pool to pick a memory 577*0Sstevel@tonic-gate * block to read. 578*0Sstevel@tonic-gate */ 579*0Sstevel@tonic-gate for (i = 0; i < RNDPOOLSIZE/4; i++) { 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* If the pool is "full", stop after one block */ 582*0Sstevel@tonic-gate if (entropy_bits + ent >= RNDPOOLSIZE * 8) { 583*0Sstevel@tonic-gate if (i > 0) 584*0Sstevel@tonic-gate break; 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate /* 588*0Sstevel@tonic-gate * This lock protects reading of phys_install. 589*0Sstevel@tonic-gate * Any changes to this list, by DR, are done while 590*0Sstevel@tonic-gate * holding this lock. So, holding this lock is sufficient 591*0Sstevel@tonic-gate * to handle DR also. 592*0Sstevel@tonic-gate */ 593*0Sstevel@tonic-gate memlist_read_lock(); 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* We're left with less than 4K of memory after DR */ 596*0Sstevel@tonic-gate ASSERT(entsrc->nblocks > 0); 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /* Pick a memory block to read */ 599*0Sstevel@tonic-gate block = oblock = srndpool[i] % entsrc->nblocks; 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate for (pmem = phys_install; pmem != NULL; pmem = pmem->next) { 602*0Sstevel@tonic-gate if (block < pmem->size / MEMBLOCKSIZE) 603*0Sstevel@tonic-gate break; 604*0Sstevel@tonic-gate block -= pmem->size / MEMBLOCKSIZE; 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate ASSERT(pmem != NULL); 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate offset = pmem->address + block * MEMBLOCKSIZE; 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate if (!address_in_memlist(phys_install, offset, MEMBLOCKSIZE)) { 612*0Sstevel@tonic-gate memlist_read_unlock(); 613*0Sstevel@tonic-gate continue; 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate /* 617*0Sstevel@tonic-gate * Figure out which page to load to read the 618*0Sstevel@tonic-gate * memory block. Load the page and compute the 619*0Sstevel@tonic-gate * hash of the memory block. 620*0Sstevel@tonic-gate */ 621*0Sstevel@tonic-gate len = MEMBLOCKSIZE; 622*0Sstevel@tonic-gate ts1 = gethrtime(); 623*0Sstevel@tonic-gate HashInit(&ctx); 624*0Sstevel@tonic-gate while (len) { 625*0Sstevel@tonic-gate pfn = offset >> PAGESHIFT; 626*0Sstevel@tonic-gate poffset = offset & PAGEOFFSET; 627*0Sstevel@tonic-gate nbytes = PAGESIZE - poffset < len ? 628*0Sstevel@tonic-gate PAGESIZE - poffset : len; 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate hat_devload(kas.a_hat, entsrc->pmbuf, 631*0Sstevel@tonic-gate PAGESIZE, pfn, PROT_READ, 632*0Sstevel@tonic-gate HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate HashUpdate(&ctx, (uint8_t *)entsrc->pmbuf + poffset, 635*0Sstevel@tonic-gate nbytes); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate hat_unload(kas.a_hat, entsrc->pmbuf, PAGESIZE, 638*0Sstevel@tonic-gate HAT_UNLOAD_UNLOCK); 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate len -= nbytes; 641*0Sstevel@tonic-gate offset += nbytes; 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate /* We got our pages. Let the DR roll */ 644*0Sstevel@tonic-gate memlist_read_unlock(); 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate HashFinal(digest, &ctx); 647*0Sstevel@tonic-gate ts2 = gethrtime(); 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate /* 650*0Sstevel@tonic-gate * Compute the time it took to load and hash the 651*0Sstevel@tonic-gate * block and compare it against the previous 652*0Sstevel@tonic-gate * measurement. The delta of the time values 653*0Sstevel@tonic-gate * provides a small amount of entropy. The 654*0Sstevel@tonic-gate * minimum of the first, second, and third order 655*0Sstevel@tonic-gate * delta is used to estimate how much entropy 656*0Sstevel@tonic-gate * is present. 657*0Sstevel@tonic-gate */ 658*0Sstevel@tonic-gate diff = ts2 - ts1; 659*0Sstevel@tonic-gate delta = diff - entsrc->last_diff; 660*0Sstevel@tonic-gate if (delta < 0) 661*0Sstevel@tonic-gate delta = -delta; 662*0Sstevel@tonic-gate delta2 = delta - entsrc->last_delta; 663*0Sstevel@tonic-gate if (delta2 < 0) 664*0Sstevel@tonic-gate delta2 = -delta2; 665*0Sstevel@tonic-gate delta3 = delta2 - entsrc->last_delta2; 666*0Sstevel@tonic-gate if (delta3 < 0) 667*0Sstevel@tonic-gate delta3 = -delta3; 668*0Sstevel@tonic-gate entsrc->last_diff = diff; 669*0Sstevel@tonic-gate entsrc->last_delta = delta; 670*0Sstevel@tonic-gate entsrc->last_delta2 = delta2; 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate if (delta > delta2) 673*0Sstevel@tonic-gate delta = delta2; 674*0Sstevel@tonic-gate if (delta > delta3) 675*0Sstevel@tonic-gate delta = delta3; 676*0Sstevel@tonic-gate delta2 = 0; 677*0Sstevel@tonic-gate while (delta >>= 1) 678*0Sstevel@tonic-gate delta2++; 679*0Sstevel@tonic-gate ent += delta2; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate /* 682*0Sstevel@tonic-gate * If the memory block has changed, credit the pool with 683*0Sstevel@tonic-gate * the entropy estimate. The entropy estimate is doubled 684*0Sstevel@tonic-gate * because the single-bit checksum misses half the change 685*0Sstevel@tonic-gate * on average. 686*0Sstevel@tonic-gate */ 687*0Sstevel@tonic-gate if (physmem_parity_update(entsrc->parity, oblock, 688*0Sstevel@tonic-gate digest[0] & 1)) 689*0Sstevel@tonic-gate ent += 2 * entsrc->entperblock; 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate /* Add the entropy bytes to the pool */ 692*0Sstevel@tonic-gate swrand_add_bytes(digest, HASHSIZE); 693*0Sstevel@tonic-gate swrand_add_bytes((uint8_t *)&ts1, sizeof (ts1)); 694*0Sstevel@tonic-gate swrand_add_bytes((uint8_t *)&ts2, sizeof (ts2)); 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate swrand_mix_pool(ent); 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate static int 701*0Sstevel@tonic-gate physmem_parity_update(uint8_t *parity_vec, uint32_t block, int parity) 702*0Sstevel@tonic-gate { 703*0Sstevel@tonic-gate /* Test and set the parity bit, return 1 if changed */ 704*0Sstevel@tonic-gate if (parity == ((parity_vec[block >> 3] >> (block & 7)) & 1)) 705*0Sstevel@tonic-gate return (0); 706*0Sstevel@tonic-gate parity_vec[block >> 3] ^= 1 << (block & 7); 707*0Sstevel@tonic-gate return (1); 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate /* Compute number of memory blocks available to scan */ 711*0Sstevel@tonic-gate static void 712*0Sstevel@tonic-gate physmem_count_blocks() 713*0Sstevel@tonic-gate { 714*0Sstevel@tonic-gate struct memlist *pmem; 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate memlist_read_lock(); 717*0Sstevel@tonic-gate entsrc.nblocks = 0; 718*0Sstevel@tonic-gate for (pmem = phys_install; pmem != NULL; pmem = pmem->next) { 719*0Sstevel@tonic-gate entsrc.nblocks += pmem->size / MEMBLOCKSIZE; 720*0Sstevel@tonic-gate if (entsrc.nblocks > MAXMEMBLOCKS) { 721*0Sstevel@tonic-gate entsrc.nblocks = MAXMEMBLOCKS; 722*0Sstevel@tonic-gate break; 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate memlist_read_unlock(); 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate /* 729*0Sstevel@tonic-gate * Dynamic Reconfiguration call-back functions 730*0Sstevel@tonic-gate */ 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate /* ARGSUSED */ 733*0Sstevel@tonic-gate static void 734*0Sstevel@tonic-gate rnd_dr_callback_post_add(void *arg, pgcnt_t delta) 735*0Sstevel@tonic-gate { 736*0Sstevel@tonic-gate /* More memory is available now, so update entsrc->nblocks. */ 737*0Sstevel@tonic-gate physmem_count_blocks(); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate /* Call-back routine invoked before the DR starts a memory removal. */ 741*0Sstevel@tonic-gate /* ARGSUSED */ 742*0Sstevel@tonic-gate static int 743*0Sstevel@tonic-gate rnd_dr_callback_pre_del(void *arg, pgcnt_t delta) 744*0Sstevel@tonic-gate { 745*0Sstevel@tonic-gate return (0); 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate /* Call-back routine invoked after the DR starts a memory removal. */ 749*0Sstevel@tonic-gate /* ARGSUSED */ 750*0Sstevel@tonic-gate static void 751*0Sstevel@tonic-gate rnd_dr_callback_post_del(void *arg, pgcnt_t delta, int cancelled) 752*0Sstevel@tonic-gate { 753*0Sstevel@tonic-gate /* Memory has shrunk, so update entsrc->nblocks. */ 754*0Sstevel@tonic-gate physmem_count_blocks(); 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate /* Timeout handling to gather entropy from physmem events */ 758*0Sstevel@tonic-gate static void 759*0Sstevel@tonic-gate swrand_schedule_timeout(void) 760*0Sstevel@tonic-gate { 761*0Sstevel@tonic-gate clock_t ut; /* time in microseconds */ 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&srndpool_lock)); 764*0Sstevel@tonic-gate /* 765*0Sstevel@tonic-gate * The new timeout value is taken from the pool of random bits. 766*0Sstevel@tonic-gate * We're merely reading the first 32 bits from the pool here, not 767*0Sstevel@tonic-gate * consuming any entropy. 768*0Sstevel@tonic-gate * This routine is usually called right after stirring the pool, so 769*0Sstevel@tonic-gate * srndpool[0] will have a *fresh* random value each time. 770*0Sstevel@tonic-gate * The timeout multiplier value is a random value between 0.7 sec and 771*0Sstevel@tonic-gate * 1.748575 sec (0.7 sec + 0xFFFFF microseconds). 772*0Sstevel@tonic-gate * The new timeout is TIMEOUT_INTERVAL times that multiplier. 773*0Sstevel@tonic-gate */ 774*0Sstevel@tonic-gate ut = 700000 + (clock_t)(srndpool[0] & 0xFFFFF); 775*0Sstevel@tonic-gate rnd_timeout_id = timeout(rnd_handler, NULL, 776*0Sstevel@tonic-gate TIMEOUT_INTERVAL * drv_usectohz(ut)); 777*0Sstevel@tonic-gate } 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate /*ARGSUSED*/ 780*0Sstevel@tonic-gate static void 781*0Sstevel@tonic-gate rnd_handler(void *arg) 782*0Sstevel@tonic-gate { 783*0Sstevel@tonic-gate mutex_enter(&srndpool_lock); 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate physmem_ent_gen(&entsrc); 786*0Sstevel@tonic-gate if (snum_waiters > 0) 787*0Sstevel@tonic-gate cv_broadcast(&srndpool_read_cv); 788*0Sstevel@tonic-gate swrand_schedule_timeout(); 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate mutex_exit(&srndpool_lock); 791*0Sstevel@tonic-gate } 792