4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Software based random number provider for the Kernel Cryptographic
28 * Framework (KCF). This provider periodically collects unpredictable input
29 * from external sources and processes it into a pool of entropy (randomness)
30 * in order to satisfy requests for random bits from kCF. It implements
31 * software-based mixing, extraction, and generation algorithms.
33 * A history note: The software-based algorithms in this file used to be
34 * part of the /dev/random driver.
37 #include <sys/types.h>
38 #include <sys/errno.h>
39 #include <sys/debug.h>
40 #include <vm/seg_kmem.h>
42 #include <sys/systm.h>
43 #include <sys/memlist.h>
44 #include <sys/cmn_err.h>
45 #include <sys/ksynch.h>
46 #include <sys/random.h>
49 #include <sys/sysmacros.h>
50 #include <sys/mem_config.h>
52 #include <sys/crypto/spi.h>
54 #include <sys/sunddi.h>
55 #include <sys/modctl.h>
56 #include <sys/hold_page.h>
57 #include <rng/fips_random.h>
59 #define RNDPOOLSIZE 1024 /* Pool size in bytes */
60 #define HASHBUFSIZE 64 /* Buffer size used for pool mixing */
61 #define MAXMEMBLOCKS 16384 /* Number of memory blocks to scan */
62 #define MEMBLOCKSIZE 4096 /* Size of memory block to read */
63 #define MINEXTRACTBITS 160 /* Min entropy level for extraction */
64 #define TIMEOUT_INTERVAL 5 /* Periodic mixing interval in secs */
66 /* Hash-algo generic definitions. For now, they are SHA1's. */
68 #define HASH_CTX SHA1_CTX
69 #define HashInit(ctx) SHA1Init((ctx))
70 #define HashUpdate(ctx, p, s) SHA1Update((ctx), (p), (s))
71 #define HashFinal(d, ctx) SHA1Final((d), (ctx))
73 /* Physical memory entropy source */
74 typedef struct physmem_entsrc_s
{
75 uint8_t *parity
; /* parity bit vector */
76 caddr_t pmbuf
; /* buffer for memory block */
77 uint32_t nblocks
; /* number of memory blocks */
78 int entperblock
; /* entropy bits per block read */
79 hrtime_t last_diff
; /* previous time to process a block */
80 hrtime_t last_delta
; /* previous time delta */
81 hrtime_t last_delta2
; /* previous 2nd order time delta */
84 static uint32_t srndpool
[RNDPOOLSIZE
/4]; /* Pool of random bits */
85 static uint32_t buffer
[RNDPOOLSIZE
/4]; /* entropy mixed in later */
86 static int buffer_bytes
; /* bytes written to buffer */
87 static uint32_t entropy_bits
; /* pool's current amount of entropy */
88 static kmutex_t srndpool_lock
; /* protects r/w accesses to the pool, */
89 /* and the global variables */
90 static kmutex_t buffer_lock
; /* protects r/w accesses to buffer */
91 static kcondvar_t srndpool_read_cv
; /* serializes poll/read syscalls */
92 static int pindex
; /* Global index for adding/extracting */
94 static int bstart
, bindex
; /* Global vars for adding/extracting */
96 static uint8_t leftover
[HASHSIZE
]; /* leftover output */
97 static uint32_t swrand_XKEY
[6]; /* one extra word for getentropy */
98 static int leftover_bytes
; /* leftover length */
99 static uint32_t previous_bytes
[HASHSIZE
/BYTES_IN_WORD
]; /* prev random bytes */
101 static physmem_entsrc_t entsrc
; /* Physical mem as an entropy source */
102 static timeout_id_t rnd_timeout_id
;
103 static int snum_waiters
;
104 static crypto_kcf_provider_handle_t swrand_prov_handle
= 0;
105 swrand_stats_t swrand_stats
;
107 static int physmem_ent_init(physmem_entsrc_t
*);
108 static void physmem_ent_fini(physmem_entsrc_t
*);
109 static void physmem_ent_gen(physmem_entsrc_t
*);
110 static int physmem_parity_update(uint8_t *, uint32_t, int);
111 static void physmem_count_blocks();
112 static void rnd_dr_callback_post_add(void *, pgcnt_t
);
113 static int rnd_dr_callback_pre_del(void *, pgcnt_t
);
114 static void rnd_dr_callback_post_del(void *, pgcnt_t
, int);
115 static void rnd_handler(void *arg
);
116 static void swrand_init();
117 static void swrand_schedule_timeout(void);
118 static int swrand_get_entropy(uint8_t *ptr
, size_t len
, boolean_t
);
119 static void swrand_add_entropy(uint8_t *ptr
, size_t len
, uint16_t entropy_est
);
120 static void swrand_add_entropy_later(uint8_t *ptr
, size_t len
);
122 /* Dynamic Reconfiguration related declarations */
123 kphysm_setup_vector_t rnd_dr_callback_vec
= {
124 KPHYSM_SETUP_VECTOR_VERSION
,
125 rnd_dr_callback_post_add
,
126 rnd_dr_callback_pre_del
,
127 rnd_dr_callback_post_del
130 extern struct mod_ops mod_cryptoops
;
133 * Module linkage information for the kernel.
135 static struct modlcrypto modlcrypto
= {
137 "Kernel Random number Provider"
140 static struct modlinkage modlinkage
= {
147 * CSPI information (entry points, provider info, etc.)
149 static void swrand_provider_status(crypto_provider_handle_t
, uint_t
*);
151 static crypto_control_ops_t swrand_control_ops
= {
152 swrand_provider_status
155 static int swrand_seed_random(crypto_provider_handle_t
, crypto_session_id_t
,
156 uchar_t
*, size_t, uint_t
, uint32_t, crypto_req_handle_t
);
157 static int swrand_generate_random(crypto_provider_handle_t
,
158 crypto_session_id_t
, uchar_t
*, size_t, crypto_req_handle_t
);
160 static crypto_random_number_ops_t swrand_random_number_ops
= {
162 swrand_generate_random
165 static crypto_ops_t swrand_crypto_ops
= {
174 &swrand_random_number_ops
,
185 static crypto_provider_info_t swrand_prov_info
= {
186 CRYPTO_SPI_VERSION_4
,
187 "Kernel Random Number Provider",
203 mutex_init(&srndpool_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
204 mutex_init(&buffer_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
205 cv_init(&srndpool_read_cv
, NULL
, CV_DEFAULT
, NULL
);
215 * Initialize the pool using
216 * . 2 unpredictable times: high resolution time since the boot-time,
217 * and the current time-of-the day.
218 * . The initial physical memory state.
221 swrand_add_entropy((uint8_t *)&ts
, sizeof (ts
), 0);
223 (void) drv_getparm(TIME
, &now
);
224 swrand_add_entropy((uint8_t *)&now
, sizeof (now
), 0);
226 ret
= kphysm_setup_func_register(&rnd_dr_callback_vec
, NULL
);
229 if (physmem_ent_init(&entsrc
) != 0) {
234 if ((ret
= mod_install(&modlinkage
)) != 0)
237 /* Schedule periodic mixing of the pool. */
238 mutex_enter(&srndpool_lock
);
239 swrand_schedule_timeout();
240 mutex_exit(&srndpool_lock
);
241 (void) swrand_get_entropy((uint8_t *)swrand_XKEY
, HASHSIZE
, B_TRUE
);
242 bcopy(swrand_XKEY
, previous_bytes
, HASHSIZE
);
244 /* Register with KCF. If the registration fails, return error. */
245 if (crypto_register_provider(&swrand_prov_info
, &swrand_prov_handle
)) {
246 (void) mod_remove(&modlinkage
);
254 physmem_ent_fini(&entsrc
);
256 mutex_destroy(&srndpool_lock
);
257 mutex_destroy(&buffer_lock
);
258 cv_destroy(&srndpool_read_cv
);
263 _info(struct modinfo
*modinfop
)
265 return (mod_info(&modlinkage
, modinfop
));
269 * Control entry points.
273 swrand_provider_status(crypto_provider_handle_t provider
, uint_t
*status
)
275 *status
= CRYPTO_PROVIDER_READY
;
279 * Random number entry points.
283 swrand_seed_random(crypto_provider_handle_t provider
, crypto_session_id_t sid
,
284 uchar_t
*buf
, size_t len
, uint_t entropy_est
, uint32_t flags
,
285 crypto_req_handle_t req
)
287 /* The entropy estimate is always 0 in this path */
288 if (flags
& CRYPTO_SEED_NOW
)
289 swrand_add_entropy(buf
, len
, 0);
291 swrand_add_entropy_later(buf
, len
);
292 return (CRYPTO_SUCCESS
);
297 swrand_generate_random(crypto_provider_handle_t provider
,
298 crypto_session_id_t sid
, uchar_t
*buf
, size_t len
, crypto_req_handle_t req
)
300 if (crypto_kmflag(req
) == KM_NOSLEEP
)
301 (void) swrand_get_entropy(buf
, len
, B_TRUE
);
303 (void) swrand_get_entropy(buf
, len
, B_FALSE
);
305 return (CRYPTO_SUCCESS
);
309 * Extraction of entropy from the pool.
311 * Returns "len" random bytes in *ptr.
312 * Try to gather some more entropy by calling physmem_ent_gen() when less than
313 * MINEXTRACTBITS are present in the pool.
314 * Will block if not enough entropy was available and the call is blocking.
317 swrand_get_entropy(uint8_t *ptr
, size_t len
, boolean_t nonblock
)
321 uint8_t digest
[HASHSIZE
], *pool
;
322 uint32_t tempout
[HASHSIZE
/BYTES_IN_WORD
];
325 mutex_enter(&srndpool_lock
);
326 if (leftover_bytes
> 0) {
327 bytes
= min(len
, leftover_bytes
);
328 bcopy(leftover
, ptr
, bytes
);
331 leftover_bytes
-= bytes
;
332 if (leftover_bytes
> 0)
333 ovbcopy(leftover
+bytes
, leftover
, leftover_bytes
);
337 /* Check if there is enough entropy */
338 while (entropy_bits
< MINEXTRACTBITS
) {
340 physmem_ent_gen(&entsrc
);
342 if (entropy_bits
< MINEXTRACTBITS
&&
343 nonblock
== B_TRUE
) {
344 mutex_exit(&srndpool_lock
);
348 if (entropy_bits
< MINEXTRACTBITS
) {
349 ASSERT(nonblock
== B_FALSE
);
351 if (cv_wait_sig(&srndpool_read_cv
,
352 &srndpool_lock
) == 0) {
354 mutex_exit(&srndpool_lock
);
361 /* Figure out how many bytes to extract */
362 bytes
= min(HASHSIZE
, len
);
363 bytes
= min(bytes
, CRYPTO_BITS2BYTES(entropy_bits
));
364 entropy_bits
-= CRYPTO_BYTES2BITS(bytes
);
365 BUMP_SWRAND_STATS(ss_entOut
, CRYPTO_BYTES2BITS(bytes
));
366 swrand_stats
.ss_entEst
= entropy_bits
;
368 /* Extract entropy by hashing pool content */
370 HashUpdate(&hashctx
, (uint8_t *)srndpool
, RNDPOOLSIZE
);
371 HashFinal(digest
, &hashctx
);
374 * Feed the digest back into the pool so next
375 * extraction produces different result
377 pool
= (uint8_t *)srndpool
;
378 for (i
= 0; i
< HASHSIZE
; i
++) {
379 pool
[pindex
++] ^= digest
[i
];
380 /* pindex modulo RNDPOOLSIZE */
381 pindex
&= (RNDPOOLSIZE
- 1);
384 /* LINTED E_BAD_PTR_CAST_ALIGN */
385 fips_random_inner(swrand_XKEY
, tempout
, (uint32_t *)digest
);
387 if (len
>= HASHSIZE
) {
390 size
= min(bytes
, HASHSIZE
);
394 * FIPS 140-2: Continuous RNG test - each generation
395 * of an n-bit block shall be compared with the previously
396 * generated block. Test shall fail if any two compared
397 * n-bit blocks are equal.
399 for (i
= 0; i
< HASHSIZE
/BYTES_IN_WORD
; i
++) {
400 if (tempout
[i
] != previous_bytes
[i
])
404 if (i
== HASHSIZE
/BYTES_IN_WORD
) {
405 cmn_err(CE_WARN
, "swrand: The value of 160-bit block "
406 "random bytes are same as the previous one.\n");
407 /* discard random bytes and return error */
411 bcopy(tempout
, previous_bytes
, HASHSIZE
);
413 bcopy(tempout
, ptr
, size
);
414 if (len
< HASHSIZE
) {
415 leftover_bytes
= HASHSIZE
- bytes
;
416 bcopy((uint8_t *)tempout
+ bytes
, leftover
,
422 BUMP_SWRAND_STATS(ss_bytesOut
, size
);
425 /* Zero out sensitive information */
426 bzero(digest
, HASHSIZE
);
427 bzero(tempout
, HASHSIZE
);
428 mutex_exit(&srndpool_lock
);
432 #define SWRAND_ADD_BYTES(ptr, len, i, pool) \
433 ASSERT((ptr) != NULL && (len) > 0); \
434 BUMP_SWRAND_STATS(ss_bytesIn, (len)); \
436 (pool)[(i)++] ^= *(ptr); \
438 (i) &= (RNDPOOLSIZE - 1); \
441 /* Write some more user-provided entropy to the pool */
443 swrand_add_bytes(uint8_t *ptr
, size_t len
)
445 uint8_t *pool
= (uint8_t *)srndpool
;
447 ASSERT(MUTEX_HELD(&srndpool_lock
));
448 SWRAND_ADD_BYTES(ptr
, len
, pindex
, pool
);
452 * Add bytes to buffer. Adding the buffer to the random pool
453 * is deferred until the random pool is mixed.
456 swrand_add_bytes_later(uint8_t *ptr
, size_t len
)
458 uint8_t *pool
= (uint8_t *)buffer
;
460 ASSERT(MUTEX_HELD(&buffer_lock
));
461 SWRAND_ADD_BYTES(ptr
, len
, bindex
, pool
);
465 #undef SWRAND_ADD_BYTES
469 swrand_mix_pool(uint16_t entropy_est
)
473 uint8_t digest
[HASHSIZE
];
474 uint8_t *pool
= (uint8_t *)srndpool
;
475 uint8_t *bp
= (uint8_t *)buffer
;
477 ASSERT(MUTEX_HELD(&srndpool_lock
));
479 /* add deferred bytes */
480 mutex_enter(&buffer_lock
);
481 if (buffer_bytes
> 0) {
482 if (buffer_bytes
>= RNDPOOLSIZE
) {
483 for (i
= 0; i
< RNDPOOLSIZE
/4; i
++) {
484 srndpool
[i
] ^= buffer
[i
];
489 for (i
= 0; i
< buffer_bytes
; i
++) {
490 pool
[pindex
++] ^= bp
[bstart
];
492 pindex
&= (RNDPOOLSIZE
- 1);
493 bstart
&= (RNDPOOLSIZE
- 1);
495 ASSERT(bstart
== bindex
);
499 mutex_exit(&buffer_lock
);
502 for (i
= 0; i
< RNDPOOLSIZE
/HASHSIZE
+ 1; i
++) {
505 /* Hash a buffer centered on a block in the pool */
506 if (start
+ HASHBUFSIZE
<= RNDPOOLSIZE
)
507 HashUpdate(&hashctx
, &pool
[start
], HASHBUFSIZE
);
509 HashUpdate(&hashctx
, &pool
[start
],
510 RNDPOOLSIZE
- start
);
511 HashUpdate(&hashctx
, pool
,
512 HASHBUFSIZE
- RNDPOOLSIZE
+ start
);
514 HashFinal(digest
, &hashctx
);
516 /* XOR the hash result back into the block */
517 k
= (start
+ HASHSIZE
) & (RNDPOOLSIZE
- 1);
518 for (j
= 0; j
< HASHSIZE
; j
++) {
519 pool
[k
++] ^= digest
[j
];
520 k
&= (RNDPOOLSIZE
- 1);
523 /* Slide the hash buffer and repeat with next block */
524 start
= (start
+ HASHSIZE
) & (RNDPOOLSIZE
- 1);
527 entropy_bits
+= entropy_est
;
528 if (entropy_bits
> CRYPTO_BYTES2BITS(RNDPOOLSIZE
))
529 entropy_bits
= CRYPTO_BYTES2BITS(RNDPOOLSIZE
);
531 swrand_stats
.ss_entEst
= entropy_bits
;
532 BUMP_SWRAND_STATS(ss_entIn
, entropy_est
);
536 swrand_add_entropy_later(uint8_t *ptr
, size_t len
)
538 mutex_enter(&buffer_lock
);
539 swrand_add_bytes_later(ptr
, len
);
540 mutex_exit(&buffer_lock
);
544 swrand_add_entropy(uint8_t *ptr
, size_t len
, uint16_t entropy_est
)
546 mutex_enter(&srndpool_lock
);
547 swrand_add_bytes(ptr
, len
);
548 swrand_mix_pool(entropy_est
);
549 mutex_exit(&srndpool_lock
);
553 * The physmem_* routines below generate entropy by reading blocks of
554 * physical memory. Entropy is gathered in a couple of ways:
556 * - By reading blocks of physical memory and detecting if changes
557 * occurred in the blocks read.
559 * - By measuring the time it takes to load and hash a block of memory
560 * and computing the differences in the measured time.
562 * The first method was used in the CryptoRand implementation. Physical
563 * memory is divided into blocks of fixed size. A block of memory is
564 * chosen from the possible blocks and hashed to produce a digest. This
565 * digest is then mixed into the pool. A single bit from the digest is
566 * used as a parity bit or "checksum" and compared against the previous
567 * "checksum" computed for the block. If the single-bit checksum has not
568 * changed, no entropy is credited to the pool. If there is a change,
569 * then the assumption is that at least one bit in the block has changed.
570 * The possible locations within the memory block of where the bit change
571 * occurred is used as a measure of entropy. For example, if a block
572 * size of 4096 bytes is used, about log_2(4096*8)=15 bits worth of
573 * entropy is available. Because the single-bit checksum will miss half
574 * of the changes, the amount of entropy credited to the pool is doubled
575 * when a change is detected. With a 4096 byte block size, a block
576 * change will add a total of 30 bits of entropy to the pool.
578 * The second method measures the amount of time it takes to read and
579 * hash a physical memory block (as described above). The time measured
580 * can vary depending on system load, scheduling and other factors.
581 * Differences between consecutive measurements are computed to come up
582 * with an entropy estimate. The first, second, and third order delta is
583 * calculated to determine the minimum delta value. The number of bits
584 * present in this minimum delta value is the entropy estimate. This
585 * entropy estimation technique using time deltas is similar to that used
586 * in /dev/random implementations from Linux/BSD.
590 physmem_ent_init(physmem_entsrc_t
*entsrc
)
595 bzero(entsrc
, sizeof (*entsrc
));
598 * The maximum entropy amount in bits per block of memory read is
599 * log_2(MEMBLOCKSIZE * 8);
601 i
= CRYPTO_BYTES2BITS(MEMBLOCKSIZE
);
603 entsrc
->entperblock
++;
605 /* Initialize entsrc->nblocks */
606 physmem_count_blocks();
608 if (entsrc
->nblocks
== 0) {
609 cmn_err(CE_WARN
, "no memory blocks to scan!");
613 /* Allocate space for the parity vector and memory page */
614 entsrc
->parity
= kmem_alloc(howmany(entsrc
->nblocks
, 8),
616 entsrc
->pmbuf
= vmem_alloc(heap_arena
, PAGESIZE
, VM_SLEEP
);
619 /* Initialize parity vector with bits from the pool */
620 i
= howmany(entsrc
->nblocks
, 8);
621 ptr
= entsrc
->parity
;
623 if (i
> RNDPOOLSIZE
) {
624 bcopy(srndpool
, ptr
, RNDPOOLSIZE
);
625 mutex_enter(&srndpool_lock
);
627 mutex_exit(&srndpool_lock
);
631 bcopy(srndpool
, ptr
, i
);
636 /* Generate some entropy to further initialize the pool */
637 mutex_enter(&srndpool_lock
);
638 physmem_ent_gen(entsrc
);
640 mutex_exit(&srndpool_lock
);
646 physmem_ent_fini(physmem_entsrc_t
*entsrc
)
648 if (entsrc
->pmbuf
!= NULL
)
649 vmem_free(heap_arena
, entsrc
->pmbuf
, PAGESIZE
);
650 if (entsrc
->parity
!= NULL
)
651 kmem_free(entsrc
->parity
, howmany(entsrc
->nblocks
, 8));
652 bzero(entsrc
, sizeof (*entsrc
));
656 physmem_ent_gen(physmem_entsrc_t
*entsrc
)
658 struct memlist
*pmem
;
659 offset_t offset
, poffset
;
661 int i
, nbytes
, len
, ent
= 0;
662 uint32_t block
, oblock
;
663 hrtime_t ts1
, ts2
, diff
, delta
, delta2
, delta3
;
664 uint8_t digest
[HASHSIZE
];
669 * Use each 32-bit quantity in the pool to pick a memory
672 for (i
= 0; i
< RNDPOOLSIZE
/4; i
++) {
674 /* If the pool is "full", stop after one block */
675 if (entropy_bits
+ ent
>= CRYPTO_BYTES2BITS(RNDPOOLSIZE
)) {
681 * This lock protects reading of phys_install.
682 * Any changes to this list, by DR, are done while
683 * holding this lock. So, holding this lock is sufficient
688 /* We're left with less than 4K of memory after DR */
689 ASSERT(entsrc
->nblocks
> 0);
691 /* Pick a memory block to read */
692 block
= oblock
= srndpool
[i
] % entsrc
->nblocks
;
694 for (pmem
= phys_install
; pmem
!= NULL
; pmem
= pmem
->ml_next
) {
695 if (block
< pmem
->ml_size
/ MEMBLOCKSIZE
)
697 block
-= pmem
->ml_size
/ MEMBLOCKSIZE
;
700 ASSERT(pmem
!= NULL
);
702 offset
= pmem
->ml_address
+ block
* MEMBLOCKSIZE
;
704 if (!address_in_memlist(phys_install
, offset
, MEMBLOCKSIZE
)) {
705 memlist_read_unlock();
710 * Do an initial check to see if the address is safe
712 if (plat_hold_page(offset
>> PAGESHIFT
, PLAT_HOLD_NO_LOCK
, NULL
)
714 memlist_read_unlock();
719 * Figure out which page to load to read the
720 * memory block. Load the page and compute the
721 * hash of the memory block.
727 pfn
= offset
>> PAGESHIFT
;
728 poffset
= offset
& PAGEOFFSET
;
729 nbytes
= PAGESIZE
- poffset
< len
?
730 PAGESIZE
- poffset
: len
;
733 * Re-check the offset, and lock the frame. If the
734 * page was given away after the above check, we'll
737 if (plat_hold_page(pfn
, PLAT_HOLD_LOCK
, &pp
) ==
741 hat_devload(kas
.a_hat
, entsrc
->pmbuf
,
742 PAGESIZE
, pfn
, PROT_READ
,
743 HAT_LOAD_NOCONSIST
| HAT_LOAD_LOCK
);
745 HashUpdate(&ctx
, (uint8_t *)entsrc
->pmbuf
+ poffset
,
748 hat_unload(kas
.a_hat
, entsrc
->pmbuf
, PAGESIZE
,
751 plat_release_page(pp
);
756 /* We got our pages. Let the DR roll */
757 memlist_read_unlock();
759 /* See if we had to bail out due to a page being given away */
763 HashFinal(digest
, &ctx
);
767 * Compute the time it took to load and hash the
768 * block and compare it against the previous
769 * measurement. The delta of the time values
770 * provides a small amount of entropy. The
771 * minimum of the first, second, and third order
772 * delta is used to estimate how much entropy
776 delta
= diff
- entsrc
->last_diff
;
779 delta2
= delta
- entsrc
->last_delta
;
782 delta3
= delta2
- entsrc
->last_delta2
;
785 entsrc
->last_diff
= diff
;
786 entsrc
->last_delta
= delta
;
787 entsrc
->last_delta2
= delta2
;
799 * If the memory block has changed, credit the pool with
800 * the entropy estimate. The entropy estimate is doubled
801 * because the single-bit checksum misses half the change
804 if (physmem_parity_update(entsrc
->parity
, oblock
,
806 ent
+= 2 * entsrc
->entperblock
;
808 /* Add the entropy bytes to the pool */
809 swrand_add_bytes(digest
, HASHSIZE
);
810 swrand_add_bytes((uint8_t *)&ts1
, sizeof (ts1
));
811 swrand_add_bytes((uint8_t *)&ts2
, sizeof (ts2
));
814 swrand_mix_pool(ent
);
818 physmem_parity_update(uint8_t *parity_vec
, uint32_t block
, int parity
)
820 /* Test and set the parity bit, return 1 if changed */
821 if (parity
== ((parity_vec
[block
>> 3] >> (block
& 7)) & 1))
823 parity_vec
[block
>> 3] ^= 1 << (block
& 7);
827 /* Compute number of memory blocks available to scan */
829 physmem_count_blocks()
831 struct memlist
*pmem
;
835 for (pmem
= phys_install
; pmem
!= NULL
; pmem
= pmem
->ml_next
) {
836 entsrc
.nblocks
+= pmem
->ml_size
/ MEMBLOCKSIZE
;
837 if (entsrc
.nblocks
> MAXMEMBLOCKS
) {
838 entsrc
.nblocks
= MAXMEMBLOCKS
;
842 memlist_read_unlock();
846 * Dynamic Reconfiguration call-back functions
851 rnd_dr_callback_post_add(void *arg
, pgcnt_t delta
)
853 /* More memory is available now, so update entsrc->nblocks. */
854 physmem_count_blocks();
857 /* Call-back routine invoked before the DR starts a memory removal. */
860 rnd_dr_callback_pre_del(void *arg
, pgcnt_t delta
)
865 /* Call-back routine invoked after the DR starts a memory removal. */
868 rnd_dr_callback_post_del(void *arg
, pgcnt_t delta
, int cancelled
)
870 /* Memory has shrunk, so update entsrc->nblocks. */
871 physmem_count_blocks();
874 /* Timeout handling to gather entropy from physmem events */
876 swrand_schedule_timeout(void)
878 clock_t ut
; /* time in microseconds */
880 ASSERT(MUTEX_HELD(&srndpool_lock
));
882 * The new timeout value is taken from the pool of random bits.
883 * We're merely reading the first 32 bits from the pool here, not
884 * consuming any entropy.
885 * This routine is usually called right after stirring the pool, so
886 * srndpool[0] will have a *fresh* random value each time.
887 * The timeout multiplier value is a random value between 0.7 sec and
888 * 1.748575 sec (0.7 sec + 0xFFFFF microseconds).
889 * The new timeout is TIMEOUT_INTERVAL times that multiplier.
891 ut
= 700000 + (clock_t)(srndpool
[0] & 0xFFFFF);
892 rnd_timeout_id
= timeout(rnd_handler
, NULL
,
893 TIMEOUT_INTERVAL
* drv_usectohz(ut
));
898 rnd_handler(void *arg
)
900 mutex_enter(&srndpool_lock
);
902 physmem_ent_gen(&entsrc
);
903 if (snum_waiters
> 0)
904 cv_broadcast(&srndpool_read_cv
);
905 swrand_schedule_timeout();
907 mutex_exit(&srndpool_lock
);