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