diff --git a/share/man/man4/random.4 b/share/man/man4/random.4
index bd55e048ff40..0805be28c782 100644
--- a/share/man/man4/random.4
+++ b/share/man/man4/random.4
@@ -1,343 +1,238 @@
 .\" Copyright (c) 2001-2015	Mark R V Murray.  All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" are met:
 .\" 1. Redistributions of source code must retain the above copyright
 .\"    notice, this list of conditions and the following disclaimer.
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
 .\"
 .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 .\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 26, 2018
+.Dd April 15, 2019
 .Dt RANDOM 4
 .Os
 .Sh NAME
 .Nm random
 .Nd the entropy device
 .Sh SYNOPSIS
 .Cd "device random"
 .Cd "options RANDOM_LOADABLE"
+.Cd "options RANDOM_ENABLE_ETHER"
 .Cd "options RANDOM_ENABLE_UMA"
 .Sh DESCRIPTION
 The
 .Nm
-device
-returns an endless supply of random bytes when read.
-It also accepts and reads data
-as any ordinary file.
+device returns an endless supply of random bytes when read.
 .Pp
 The generator will start in an
 .Em unseeded
-state, and will block reads until
-it is seeded for the first time.
-This may cause trouble at system boot
-when keys and the like
-are generated from
-.Nm
-so steps should be taken to ensure a
-seeding as soon as possible.
-.Pp
-It is also possible
-to read random bytes
-by using the KERN_ARND sysctl.
-On the command line
-this could be done by
-.Pp
-.Dl "sysctl -x -B 16 kern.arandom"
-.Pp
-This sysctl will not return
-random bytes unless
-the
-.Nm
-device is seeded.
+state, and will block reads until it is seeded for the first time.
 .Pp
-This initial seeding
-of random number generators
-is a bootstrapping problem
-that needs very careful attention.
-In some cases,
-it may be difficult
-to find enough randomness
-to seed a random number generator
-until a system is fully operational,
-but the system requires random numbers
-to become fully operational.
-It is (or more accurately should be)
-critically important that the
-.Nm
-device is seeded
-before the first time it is used.
-In the case where a dummy or "blocking-only"
-device is used,
-it is the responsibility
-of the system architect
-to ensure that no blocking reads
-hold up critical processes.
+To provide prompt access to the random device at boot time,
+.Fx
+automatically persists some entropy data in
+.Pa /boot/entropy
+for the loader to provide to the kernel.
+Additional entropy is regularly saved in
+.Pa /var/db/entropy .
+This saved entropy is sufficient to unblock the random device on devices with
+writeable media.
+.Pp
+Embedded applications without writable media must determine their own scheme
+for re-seeding the random device on boot, or accept that the device
+will remain unseeded and block reads indefinitely.
+See
+.Sx SECURITY CONSIDERATIONS
+for more detail.
+.Pp
+In addition to
+.Xr read 2 ,
+the direct output of the abstract kernel entropy device can be read with
+.Xr getrandom 2 ,
+.Xr getentropy 3 ,
+or the
+.Xr sysctl 8
+pseudo-variable
+.Va kern.arandom .
 .Pp
 To see the current settings of the software
 .Nm
 device, use the command line:
 .Pp
 .Dl "sysctl kern.random"
 .Pp
 which results in something like:
 .Bd -literal -offset indent
+kern.random.block_seeded_status: 0
 kern.random.fortuna.minpoolsize: 64
-kern.random.harvest.mask_symbolic: [HIGH_PERFORMANCE], ... ,CACHED
-kern.random.harvest.mask_bin: 00111111111
-kern.random.harvest.mask: 511
+kern.random.harvest.mask_symbolic: ENABLEDSOURCE,[DISABLEDSOURCE],...,CACHED
+kern.random.harvest.mask_bin: 00000010000000111011111
+kern.random.harvest.mask: 66015
+kern.random.use_chacha20_cipher: 0
 kern.random.random_sources: 'Intel Secure Key RNG'
 .Ed
 .Pp
 Other than
-.Dl kern.random.fortuna.minpoolsize
+.Va kern.random.block_seeded_status ,
+.Va kern.random.fortuna.minpoolsize ,
 and
-.Dl kern.random.harvest.mask
+.Va kern.random.harvest.mask ,
 all settings are read-only.
 .Pp
 The
 .Pa kern.random.fortuna.minpoolsize
 sysctl is used
 to set the seed threshold.
 A smaller number gives a faster seed,
 but a less secure one.
 In practice,
 values between 64 and 256
 are acceptable.
 .Pp
 The
 .Va kern.random.harvest.mask
 bitmask is used to select
 the possible entropy sources.
 A 0 (zero) value means
 the corresponding source
 is not considered
 as an entropy source.
 Set the bit to 1 (one)
 if you wish to use
 that source.
 The
 .Va kern.random.harvest.mask_bin
 and
 .Va kern.random.harvest.mask_symbolic
 sysctls
 can be used to confirm
-that the choices are correct.
-Note that disabled items
+settings in a human readable form.
+Disabled items
 in the latter item
 are listed in square brackets.
 See
 .Xr random_harvest 9
 for more on the harvesting of entropy.
+.Sh FILES
+.Bl -tag -width ".Pa /dev/urandom"
+.It Pa /dev/random
+.It Pa /dev/urandom
+.El
+.Sh SEE ALSO
+.Xr getrandom 2 ,
+.Xr arc4random 3 ,
+.Xr getentropy 3 ,
+.Xr random 3 ,
+.Xr sysctl 8 ,
+.Xr random 9
+.Rs
+.%A Ferguson
+.%A Schneier
+.%A Kohno
+.%B Cryptography Engineering
+.%I Wiley
+.%O ISBN 978-0-470-47424-2
+.Re
+.Sh HISTORY
+A
+.Nm
+device appeared in
+.Fx 2.2 .
+The implementation was changed to the
+.Em Yarrow algorithm in
+.Fx 5.0 .
+In
+.Fx 11.0 ,
+the Fortuna algorithm was introduced as the default.
+In
+.Fx 12.0 ,
+Yarrow was removed entirely.
+.Sh AUTHORS
+.An -nosplit
+The current
+.Nm
+code was authored by
+.An Mark R V Murray ,
+with significant contributions from many people.
 .Pp
+The
+.Em Fortuna
+algorithm was designed by
+.An Niels Ferguson ,
+.An Bruce Schneier ,
+and
+.An Tadayoshi Kohno .
+.Sh CAVEATS
 When
 .Cd "options RANDOM_LOADABLE"
-is used,
+is enabled,
 the
 .Pa /dev/random
 device is not created
 until an "algorithm module"
 is loaded.
 The only module built by default is
 .Em random_fortuna .
-The
-.Em random_yarrow
-module was removed in
-.Fx 12 .
-Note that this loadable module
-is slightly less efficient
-than its compiled-in equivalent.
+Loadable random modules
+are less efficient
+than their compiled-in equivalents.
 This is because some functions
 must be locked against
 load and unload events,
 and also must be indirect calls
 to allow for removal.
 .Pp
 When
 .Cd "options RANDOM_ENABLE_UMA"
-is used,
+is enabled,
 the
 .Pa /dev/random
 device will obtain entropy
 from the zone allocator.
-This is potentially very high rate,
-and if so will be of questionable use.
-If this is the case,
-use of this option
-is not recommended.
-Determining this is not trivial,
-so experimenting and measurement
-using tools such as
-.Xr dtrace 1
-will be required.
-.Sh RANDOMNESS
-The use of randomness in the field of computing
-is a rather subtle issue because randomness means
-different things to different people.
-Consider generating a password randomly,
-simulating a coin tossing experiment or
-choosing a random back-off period when a server does not respond.
-Each of these tasks requires random numbers,
-but the random numbers in each case have different requirements.
+This is a very high rate source with significant performance impact.
+Therefore, it is disabled by default.
 .Pp
-Generation of passwords, session keys and the like
-requires cryptographic randomness.
-A cryptographic random number generator should be designed
-so that its output is difficult to guess,
-even if a lot of auxiliary information is known
-(such as when it was seeded, subsequent or previous output, and so on).
-On
-.Fx ,
-seeding for cryptographic random number generators is provided by the
-.Nm
-device,
-which provides real randomness.
-The
-.Xr arc4random 3
-library call provides a pseudo-random sequence
-which is generally reckoned to be suitable for
-simple cryptographic use.
-The OpenSSL library also provides functions for managing randomness
-via functions such as
-.Xr RAND_bytes 3
-and
-.Xr RAND_add 3 .
-Note that OpenSSL uses the
+When
+.Cd "options RANDOM_ENABLE_ETHER"
+is enabled, the
 .Nm
-device for seeding automatically.
+device will obtain entropy from
+.Vt mbuf
+structures passing through the network stack.
+This source is both extremely expensive and a poor source of entropy, so it is
+disabled by default.
+.Sh SECURITY CONSIDERATIONS
+The initial seeding
+of random number generators
+is a bootstrapping problem
+that needs very careful attention.
+When writable media is available, the
+.Em Fortuna
+paper describes a robust system for rapidly reseeding the device.
 .Pp
-Randomness for simulation is required in engineering or
-scientific software and games.
-The first requirement of these applications is
-that the random numbers produced conform to some well-known,
-usually uniform, distribution.
-The sequence of numbers should also appear numerically uncorrelated,
-as simulation often assumes independence of its random inputs.
-Often it is desirable to reproduce
-the results of a simulation exactly,
-so that if the generator is seeded in the same way,
-it should produce the same results.
-A peripheral concern for simulation is
-the speed of a random number generator.
+In some embedded cases, it may be difficult to find enough randomness to seed a
+random number generator until a system is fully operational.
+In these cases, is the responsibility of the system architect to ensure that
+blocking is acceptable, or that the random device is seeded.
+(This advice does not apply to typical consumer systems.)
 .Pp
-Another issue in simulation is
-the size of the state associated with the random number generator, and
-how frequently it repeats itself.
-For example,
-a program which shuffles a pack of cards should have 52!\& possible outputs,
-which requires the random number generator to have 52!\& starting states.
-This means the seed should have at least log_2(52!) ~ 226 bits of state
-if the program is to stand a chance of outputting all possible sequences,
-and the program needs some unbiased way of generating these bits.
-Again,
-the
-.Nm
-device could be used for seeding here,
-but in practice, smaller seeds are usually considered acceptable.
-.Pp
-.Fx
-provides two families of functions which are considered
-suitable for simulation.
-The
-.Xr random 3
-family of functions provides a random integer
-between 0 to
-.if t 2\u\s731\s10\d\(mi1.
-.if n (2**31)\(mi1.
-The functions
-.Xr srandom 3 ,
-.Xr initstate 3
-and
-.Xr setstate 3
-are provided for deterministically setting
-the state of the generator and
-the function
-.Xr srandomdev 3
-is provided for setting the state via the
+To emulate embedded systems, developers may set the
+.Va kern.random.block_seeded_status
+tunable to 1 to verify boot does not require early availability of the
 .Nm
 device.
-The
-.Xr drand48 3
-family of functions are also provided,
-which provide random floating point numbers in various ranges.
-.Pp
-Randomness that is used for collision avoidance
-(for example, in certain network protocols)
-has slightly different semantics again.
-It is usually expected that the numbers will be uniform,
-as this produces the lowest chances of collision.
-Here again,
-the seeding of the generator is very important,
-as it is required that different instances of
-the generator produce independent sequences.
-However, the guessability or reproducibility of the sequence is unimportant,
-unlike the previous cases.
-.Pp
-.Fx
-does also provide the traditional
-.Xr rand 3
-library call,
-for compatibility purposes.
-However,
-it is known to be poor for simulation and
-absolutely unsuitable for cryptographic purposes,
-so its use is discouraged.
-.Sh FILES
-.Bl -tag -width ".Pa /dev/random"
-.It Pa /dev/random
-.El
-.Sh SEE ALSO
-.Xr arc4random 3 ,
-.Xr drand48 3 ,
-.Xr rand 3 ,
-.Xr RAND_add 3 ,
-.Xr RAND_bytes 3 ,
-.Xr random 3 ,
-.Xr sysctl 8 ,
-.Xr random 9
-.Rs
-.%A Ferguson
-.%A Schneier
-.%A Kohno
-.%B Cryptography Engineering
-.%I Wiley
-.%O ISBN 978-0-470-47424-2
-.Re
-.Sh HISTORY
-A
-.Nm
-device appeared in
-.Fx 2.2 .
-The current software implementation,
-introduced in
-.Fx 10.0 ,
-is by
-.An Mark R V Murray ,
-and is an implementation of the
-.Em Fortuna
-algorithm by Ferguson
-.Em et al .
-It replaces the previous
-.Em Yarrow
-implementation,
-introduced in
-.Fx 5.0 .
-The Yarrow algorithm
-is no longer supported
-by its authors,
-and is therefore no longer available.
diff --git a/share/man/man9/random.9 b/share/man/man9/random.9
index e2875e1798de..2e6189790412 100644
--- a/share/man/man9/random.9
+++ b/share/man/man9/random.9
@@ -1,212 +1,217 @@
 .\"
 .\" Copyright (c) 2015
 .\"	Mark R V Murray
 .\" Copyright (c) 2000
 .\"	The Regents of the University of California.  All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" are met:
 .\" 1. Redistributions of source code must retain the above copyright
 .\"    notice, this list of conditions and the following disclaimer.
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
 .\"
 .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
 .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
 .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\" $FreeBSD$
 .\" "
-.Dd July 16, 2015
+.Dd April 15, 2019
 .Dt RANDOM 9
 .Os
 .Sh NAME
 .Nm arc4rand ,
 .Nm arc4random ,
+.Nm arc4random_buf ,
 .Nm random ,
 .Nm read_random ,
 .Nm read_random_uio ,
 .Nm srandom
 .Nd supply pseudo-random numbers
 .Sh SYNOPSIS
 .In sys/libkern.h
+.Ft uint32_t
+.Fn arc4random "void"
 .Ft void
-.Fn srandom "u_long seed"
-.Ft u_long
-.Fn random "void"
+.Fn arc4random_buf "void *ptr" "size_t len"
 .Ft void
 .Fn arc4rand "void *ptr" "u_int length" "int reseed"
-.Ft uint32_t
-.Fn arc4random "void"
 .Pp
 .In sys/random.h
-.Ft int
+.Ft void
 .Fn read_random "void *buffer" "int count"
 .Ft int
 .Fn read_random_uio "struct uio *uio" "bool nonblock"
+.Ss LEGACY ROUTINES
+.In sys/libkern.h
+.Ft void
+.Fn srandom "u_long seed"
+.Ft u_long
+.Fn random "void"
 .Sh DESCRIPTION
 The
-.Fn random
-function will by default produce
-a sequence of numbers
-that can be duplicated
-by calling
-.Fn srandom
-with some constant
-as the
-.Fa seed .
-The
-.Fn srandom
-function may be called with any arbitrary
-.Fa seed
-value to get slightly more unpredictable numbers.
-It is important to remember that the
-.Fn random
-function is entirely predictable,
-and is therefore not of use where
-knowledge of the sequence of numbers
-may be of benefit to an attacker.
+.Fn arc4random
+and
+.Fn arc4random_buf
+functions will return very good quality random numbers, suited for
+security-related purposes.
+Both are wrappers around the underlying
+.Fn arc4rand
+interface.
+.Fn arc4random
+returns a 32-bit random value, while
+.Fn arc4random_buf
+fills
+.Fa ptr
+with
+.Fa len
+bytes of random data.
 .Pp
 The
 .Fn arc4rand
-function will return very good quality random numbers,
-better suited
-for security-related purposes.
-The random numbers from
-.Fn arc4rand
-are seeded from the entropy device
-if it is available.
-Automatic reseeds happen
-after a certain timeinterval
-and after a certain number of bytes
-have been delivered.
-A forced reseed
-can be forced
-by passing a non-zero
-value in the
+CSPRNG
+is seeded from the
+.Xr random 4
+kernel abstract entropy device.
+Automatic reseeding happens at unspecified time and bytes (of output)
+intervals.
+A reseed can be forced by passing a non-zero
 .Fa reseed
-argument.
+value.
 .Pp
 The
 .Fn read_random
-function is used to return entropy directly from the entropy device
-if it has been loaded.
-If the entropy device is not loaded, then
-the
-.Fa buffer
-is ignored
-and zero is returned.
-The
+function is used to read entropy directly from the kernel abstract entropy
+device.
+.Fn read_random
+blocks if and until the entropy device is seeded.
+The provided
 .Fa buffer
 is filled with no more than
 .Fa count
 bytes.
 It is strongly advised that
 .Fn read_random
-is not used;
-instead use
+is not used directly;
+instead, use the
 .Fn arc4rand
-unless it is
-necessary to know
-that no entropy
-has been returned.
+family of functions.
 .Pp
 The
 .Fn read_random_uio
 function behaves identically to
 .Xr read 2
 on
 .Pa /dev/random .
 The
 .Fa uio
 argument points to a buffer where random data should be stored.
-This function only returns data if the random device is seeded.
-It blocks if unseeded,
-except when the
+If
 .Fa nonblock
-argument is true.
+is true and the random device is not seeded, this function does not return any
+data.
+Otherwise, this function may block interruptibly until the random device is seeded.
+If the function is interrupted before the random device is seeded, no data is
+returned.
 .Pp
-All the bits returned by
-.Fn random ,
-.Fn arc4rand ,
-.Fn read_random ,
-and
-.Fn read_random_uio
-are usable.
-For example,
-.Sq Li random()&01
-will produce a random binary value.
-.Pp
-The
-.Fn arc4random
-is a convenience function which calls
-.Fn arc4rand
-to return a 32 bit pseudo-random integer.
-.Sh RETURN VALUES
-The
+The legacy
 .Fn random
-function uses
-a non-linear additive feedback random number generator
-employing a default table
-of size 31
-containing long integers
-to return successive pseudo-random
-numbers in the range from 0 to
-.if t 2\u\s731\s10\d\(mi1.
-.if n (2**31)\(mi1.
-The period of this random number generator
-is very large,
-approximately
-.if t 16\(mu(2\u\s731\s10\d\(mi1).
-.if n 16*((2**31)\(mi1).
-.Pp
+function will produce a sequence of numbers that can be duplicated by calling
+.Fn srandom
+with some constant as the
+.Fa seed .
+The legacy
+.Fn srandom
+function may be called with any
+.Fa seed
+value.
+It is strongly advised that the
+.Fn random
+function not be used to generate random numbers.
+See
+.Sx SECURITY CONSIDERATIONS .
+.Sh RETURN VALUES
 The
 .Fn arc4rand
-function uses the RC4 algorithm
-to generate successive pseudo-random bytes.
+function uses the Chacha20 algorithm to generate a pseudo-random sequence of
+bytes.
 The
 .Fn arc4random
 function uses
 .Fn arc4rand
 to generate pseudo-random numbers
 in the range from 0 to
 .if t 2\u\s732\s10\d\(mi1.
 .if n (2**32)\(mi1.
 .Pp
 The
 .Fn read_random
 function returns
 the number of bytes placed in
 .Fa buffer .
 .Pp
 .Fn read_random_uio
 returns zero when successful,
 otherwise an error code is returned.
+.Pp
+The legacy
+.Fn random
+function uses
+a non-linear additive feedback random number generator
+employing a default table
+of size 31
+containing long integers
+to return successive pseudo-random
+numbers in the range from 0 to
+.if t 2\u\s731\s10\d\(mi1.
+.if n (2**31)\(mi1.
+The period of this random number generator
+is very large,
+approximately
+.if t 16\(mu(2\u\s731\s10\d\(mi1).
+.if n 16*((2**31)\(mi1).
 .Sh ERRORS
 .Fn read_random_uio
 may fail if:
 .Bl -tag -width Er
 .It Bq Er EFAULT
 .Fa uio
 points to an invalid memory region.
 .It Bq Er EWOULDBLOCK
 The random device is unseeded and
 .Fa nonblock
 is true.
 .El
 .Sh AUTHORS
 .An Dan Moschuk
 wrote
 .Fn arc4random .
 .An Mark R V Murray
 wrote
 .Fn read_random .
+.Sh SECURITY CONSIDERATIONS
+Do not use
+.Fn random
+or
+.Fn srandom
+in new code.
+.Pp
+It is important to remember that the
+.Fn random
+function is entirely predictable.
+It is easy for attackers to predict future output of
+.Fn random
+by recording some generated values.
+We cannot emphasize strongly enough that
+.Fn random
+must not be used to generate values that are intended to be unpredictable.
diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
index e8a407525138..a6cfccaa3a1a 100644
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -1,467 +1,473 @@
 /*-
  * Copyright (c) 2017 W. Dean Freeman
  * Copyright (c) 2013-2015 Mark R V Murray
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
 
 /*
  * This implementation of Fortuna is based on the descriptions found in
  * ISBN 978-0-470-47424-2 "Cryptography Engineering" by Ferguson, Schneier
  * and Kohno ("FS&K").
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/limits.h>
 
 #ifdef _KERNEL
 #include <sys/fail.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/random.h>
 #include <sys/sdt.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
 #include <machine/cpu.h>
 #else /* !_KERNEL */
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <threads.h>
 
 #include "unit_test.h"
 #endif /* _KERNEL */
 
 #include <crypto/rijndael/rijndael-api-fst.h>
 #include <crypto/sha2/sha256.h>
 
 #include <dev/random/hash.h>
 #include <dev/random/randomdev.h>
 #ifdef _KERNEL
 #include <dev/random/random_harvestq.h>
 #endif
 #include <dev/random/uint128.h>
 #include <dev/random/fortuna.h>
 
 /* Defined in FS&K */
 #define	RANDOM_FORTUNA_NPOOLS 32		/* The number of accumulation pools */
 #define	RANDOM_FORTUNA_DEFPOOLSIZE 64		/* The default pool size/length for a (re)seed */
 #define	RANDOM_FORTUNA_MAX_READ (1 << 20)	/* Max bytes in a single read */
 
 /*
  * The allowable range of RANDOM_FORTUNA_DEFPOOLSIZE. The default value is above.
  * Making RANDOM_FORTUNA_DEFPOOLSIZE too large will mean a long time between reseeds,
  * and too small may compromise initial security but get faster reseeds.
  */
 #define	RANDOM_FORTUNA_MINPOOLSIZE 16
 #define	RANDOM_FORTUNA_MAXPOOLSIZE INT_MAX 
 CTASSERT(RANDOM_FORTUNA_MINPOOLSIZE <= RANDOM_FORTUNA_DEFPOOLSIZE);
 CTASSERT(RANDOM_FORTUNA_DEFPOOLSIZE <= RANDOM_FORTUNA_MAXPOOLSIZE);
 
 /* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
 CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t));
 CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE);
 
 /* Probes for dtrace(1) */
 #ifdef _KERNEL
 SDT_PROVIDER_DECLARE(random);
 SDT_PROVIDER_DEFINE(random);
 SDT_PROBE_DEFINE2(random, fortuna, event_processor, debug, "u_int", "struct fs_pool *");
 #endif /* _KERNEL */
 
 /*
  * This is the beastie that needs protecting. It contains all of the
  * state that we are excited about. Exactly one is instantiated.
  */
 static struct fortuna_state {
 	struct fs_pool {		/* P_i */
 		u_int fsp_length;	/* Only the first one is used by Fortuna */
 		struct randomdev_hash fsp_hash;
 	} fs_pool[RANDOM_FORTUNA_NPOOLS];
 	u_int fs_reseedcount;		/* ReseedCnt */
 	uint128_t fs_counter;		/* C */
 	union randomdev_key fs_key;	/* K */
 	u_int fs_minpoolsize;		/* Extras */
 	/* Extras for the OS */
 #ifdef _KERNEL
 	/* For use when 'pacing' the reseeds */
 	sbintime_t fs_lasttime;
 #endif
 	/* Reseed lock */
 	mtx_t fs_mtx;
 } fortuna_state;
 
 #ifdef _KERNEL
 static struct sysctl_ctx_list random_clist;
 RANDOM_CHECK_UINT(fs_minpoolsize, RANDOM_FORTUNA_MINPOOLSIZE, RANDOM_FORTUNA_MAXPOOLSIZE);
 #else
 static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE];
 #endif
 
 static void random_fortuna_pre_read(void);
 static void random_fortuna_read(uint8_t *, u_int);
 static bool random_fortuna_seeded(void);
 static void random_fortuna_process_event(struct harvest_event *);
 static void random_fortuna_init_alg(void *);
 static void random_fortuna_deinit_alg(void *);
 
 static void random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount);
 
 struct random_algorithm random_alg_context = {
 	.ra_ident = "Fortuna",
 	.ra_init_alg = random_fortuna_init_alg,
 	.ra_deinit_alg = random_fortuna_deinit_alg,
 	.ra_pre_read = random_fortuna_pre_read,
 	.ra_read = random_fortuna_read,
 	.ra_seeded = random_fortuna_seeded,
 	.ra_event_processor = random_fortuna_process_event,
 	.ra_poolcount = RANDOM_FORTUNA_NPOOLS,
 };
 
 /* ARGSUSED */
 static void
 random_fortuna_init_alg(void *unused __unused)
 {
 	int i;
 #ifdef _KERNEL
 	struct sysctl_oid *random_fortuna_o;
 #endif
 
 	RANDOM_RESEED_INIT_LOCK();
 	/*
 	 * Fortuna parameters. Do not adjust these unless you have
 	 * have a very good clue about what they do!
 	 */
 	fortuna_state.fs_minpoolsize = RANDOM_FORTUNA_DEFPOOLSIZE;
 #ifdef _KERNEL
 	fortuna_state.fs_lasttime = 0;
 	random_fortuna_o = SYSCTL_ADD_NODE(&random_clist,
 		SYSCTL_STATIC_CHILDREN(_kern_random),
 		OID_AUTO, "fortuna", CTLFLAG_RW, 0,
 		"Fortuna Parameters");
 	SYSCTL_ADD_PROC(&random_clist,
 		SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO,
 		"minpoolsize", CTLTYPE_UINT | CTLFLAG_RWTUN,
 		&fortuna_state.fs_minpoolsize, RANDOM_FORTUNA_DEFPOOLSIZE,
 		random_check_uint_fs_minpoolsize, "IU",
 		"Minimum pool size necessary to cause a reseed");
 	KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0 at startup"));
 #endif
 
 	/*-
 	 * FS&K - InitializePRNG()
 	 *      - P_i = \epsilon
 	 *      - ReseedCNT = 0
 	 */
 	for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) {
 		randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash);
 		fortuna_state.fs_pool[i].fsp_length = 0;
 	}
 	fortuna_state.fs_reseedcount = 0;
 	/*-
 	 * FS&K - InitializeGenerator()
 	 *      - C = 0
 	 *      - K = 0
 	 */
 	fortuna_state.fs_counter = UINT128_ZERO;
 	explicit_bzero(&fortuna_state.fs_key, sizeof(fortuna_state.fs_key));
 }
 
 /* ARGSUSED */
 static void
 random_fortuna_deinit_alg(void *unused __unused)
 {
 
 	RANDOM_RESEED_DEINIT_LOCK();
 	explicit_bzero(&fortuna_state, sizeof(fortuna_state));
 #ifdef _KERNEL
 	sysctl_ctx_free(&random_clist);
 #endif
 }
 
 /*-
  * FS&K - AddRandomEvent()
  * Process a single stochastic event off the harvest queue
  */
 static void
 random_fortuna_process_event(struct harvest_event *event)
 {
 	u_int pl;
 
 	RANDOM_RESEED_LOCK();
 	/*-
 	 * FS&K - P_i = P_i|<harvested stuff>
 	 * Accumulate the event into the appropriate pool
 	 * where each event carries the destination information.
 	 *
 	 * The hash_init() and hash_finish() calls are done in
 	 * random_fortuna_pre_read().
 	 *
 	 * We must be locked against pool state modification which can happen
 	 * during accumulation/reseeding and reading/regating.
 	 */
 	pl = event->he_destination % RANDOM_FORTUNA_NPOOLS;
 	/*
 	 * We ignore low entropy static/counter fields towards the end of the
 	 * he_event structure in order to increase measurable entropy when
 	 * conducting SP800-90B entropy analysis measurements of seed material
 	 * fed into PRNG.
 	 * -- wdf
 	 */
 	KASSERT(event->he_size <= sizeof(event->he_entropy),
 	    ("%s: event->he_size: %hhu > sizeof(event->he_entropy): %zu\n",
 	    __func__, event->he_size, sizeof(event->he_entropy)));
 	randomdev_hash_iterate(&fortuna_state.fs_pool[pl].fsp_hash,
 	    &event->he_somecounter, sizeof(event->he_somecounter));
 	randomdev_hash_iterate(&fortuna_state.fs_pool[pl].fsp_hash,
 	    event->he_entropy, event->he_size);
 
 	/*-
 	 * Don't wrap the length.  This is a "saturating" add.
 	 * XXX: FIX!!: We don't actually need lengths for anything but fs_pool[0],
 	 * but it's been useful debugging to see them all.
 	 */
 	fortuna_state.fs_pool[pl].fsp_length = MIN(RANDOM_FORTUNA_MAXPOOLSIZE,
 	    fortuna_state.fs_pool[pl].fsp_length +
 	    sizeof(event->he_somecounter) + event->he_size);
 	explicit_bzero(event, sizeof(*event));
 	RANDOM_RESEED_UNLOCK();
 }
 
 /*-
  * FS&K - Reseed()
  * This introduces new key material into the output generator.
  * Additionally it increments the output generator's counter
  * variable C. When C > 0, the output generator is seeded and
  * will deliver output.
  * The entropy_data buffer passed is a very specific size; the
  * product of RANDOM_FORTUNA_NPOOLS and RANDOM_KEYSIZE.
  */
 static void
 random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount)
 {
 	struct randomdev_hash context;
 	uint8_t hash[RANDOM_KEYSIZE];
 	const void *keymaterial;
 	size_t keysz;
 	bool seeded;
 
 	RANDOM_RESEED_ASSERT_LOCK_OWNED();
 
 	seeded = random_fortuna_seeded();
 	if (seeded) {
 		randomdev_getkey(&fortuna_state.fs_key, &keymaterial, &keysz);
 		KASSERT(keysz == RANDOM_KEYSIZE, ("%s: key size %zu not %u",
 			__func__, keysz, (unsigned)RANDOM_KEYSIZE));
 	}
 
 	/*-
 	 * FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m))
 	 *      - C = C + 1
 	 */
 	randomdev_hash_init(&context);
 	randomdev_hash_iterate(&context, zero_region, RANDOM_ZERO_BLOCKSIZE);
 	if (seeded)
 		randomdev_hash_iterate(&context, keymaterial, keysz);
 	randomdev_hash_iterate(&context, entropy_data, RANDOM_KEYSIZE*blockcount);
 	randomdev_hash_finish(&context, hash);
 	randomdev_hash_init(&context);
 	randomdev_hash_iterate(&context, hash, RANDOM_KEYSIZE);
 	randomdev_hash_finish(&context, hash);
 	randomdev_encrypt_init(&fortuna_state.fs_key, hash);
 	explicit_bzero(hash, sizeof(hash));
 	/* Unblock the device if this is the first time we are reseeding. */
 	if (uint128_is_zero(fortuna_state.fs_counter))
 		randomdev_unblock();
 	uint128_increment(&fortuna_state.fs_counter);
 }
 
 /*-
  * FS&K - GenerateBlocks()
  * Generate a number of complete blocks of random output.
  */
 static __inline void
 random_fortuna_genblocks(uint8_t *buf, u_int blockcount)
 {
 
 	RANDOM_RESEED_ASSERT_LOCK_OWNED();
 	KASSERT(!uint128_is_zero(fortuna_state.fs_counter), ("FS&K: C != 0"));
 
 	/*
 	 * Fills buf with RANDOM_BLOCKSIZE * blockcount bytes of keystream.
 	 * Increments fs_counter as it goes.
 	 */
 	randomdev_keystream(&fortuna_state.fs_key, &fortuna_state.fs_counter,
 	    buf, blockcount);
 }
 
 /*-
  * FS&K - PseudoRandomData()
  * This generates no more than 2^20 bytes of data, and cleans up its
  * internal state when finished. It is assumed that a whole number of
  * blocks are available for writing; any excess generated will be
  * ignored.
  */
 static __inline void
 random_fortuna_genrandom(uint8_t *buf, u_int bytecount)
 {
 	uint8_t temp[RANDOM_BLOCKSIZE * RANDOM_KEYS_PER_BLOCK];
 	u_int blockcount;
 
 	RANDOM_RESEED_ASSERT_LOCK_OWNED();
 	/*-
 	 * FS&K - assert(n < 2^20 (== 1 MB)
 	 *      - r = first-n-bytes(GenerateBlocks(ceil(n/16)))
 	 *      - K = GenerateBlocks(2)
 	 */
 	KASSERT((bytecount <= RANDOM_FORTUNA_MAX_READ), ("invalid single read request to Fortuna of %d bytes", bytecount));
 	blockcount = howmany(bytecount, RANDOM_BLOCKSIZE);
 	random_fortuna_genblocks(buf, blockcount);
 	random_fortuna_genblocks(temp, RANDOM_KEYS_PER_BLOCK);
 	randomdev_encrypt_init(&fortuna_state.fs_key, temp);
 	explicit_bzero(temp, sizeof(temp));
 }
 
 /*-
  * FS&K - RandomData() (Part 1)
  * Used to return processed entropy from the PRNG. There is a pre_read
  * required to be present (but it can be a stub) in order to allow
  * specific actions at the begin of the read.
  */
 void
 random_fortuna_pre_read(void)
 {
 #ifdef _KERNEL
 	sbintime_t now;
 #endif
 	struct randomdev_hash context;
 	uint32_t s[RANDOM_FORTUNA_NPOOLS*RANDOM_KEYSIZE_WORDS];
 	uint8_t temp[RANDOM_KEYSIZE];
 	u_int i;
 
 	KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0"));
 	RANDOM_RESEED_LOCK();
 #ifdef _KERNEL
 	/* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
 	now = getsbinuptime();
 #endif
 
 	if (fortuna_state.fs_pool[0].fsp_length < fortuna_state.fs_minpoolsize
 #ifdef _KERNEL
 	    /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
 	    || (now - fortuna_state.fs_lasttime <= SBT_1S/10)
 #endif
 	) {
 		RANDOM_RESEED_UNLOCK();
 		return;
 	}
 
 #ifdef _KERNEL
 	/*
 	 * When set, pretend we do not have enough entropy to reseed yet.
 	 */
 	KFAIL_POINT_CODE(DEBUG_FP, random_fortuna_pre_read, {
 		if (RETURN_VALUE != 0) {
 			RANDOM_RESEED_UNLOCK();
 			return;
 		}
 	});
 #endif
 
 #ifdef _KERNEL
 	fortuna_state.fs_lasttime = now;
 #endif
 
 	/* FS&K - ReseedCNT = ReseedCNT + 1 */
 	fortuna_state.fs_reseedcount++;
 	/* s = \epsilon at start */
 	for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) {
 		/* FS&K - if Divides(ReseedCnt, 2^i) ... */
 		if ((fortuna_state.fs_reseedcount % (1 << i)) == 0) {
 			/*-
 			    * FS&K - temp = (P_i)
 			    *      - P_i = \epsilon
 			    *      - s = s|H(temp)
 			    */
 			randomdev_hash_finish(&fortuna_state.fs_pool[i].fsp_hash, temp);
 			randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash);
 			fortuna_state.fs_pool[i].fsp_length = 0;
 			randomdev_hash_init(&context);
 			randomdev_hash_iterate(&context, temp, RANDOM_KEYSIZE);
 			randomdev_hash_finish(&context, s + i*RANDOM_KEYSIZE_WORDS);
 		} else
 			break;
 	}
 #ifdef _KERNEL
 	SDT_PROBE2(random, fortuna, event_processor, debug, fortuna_state.fs_reseedcount, fortuna_state.fs_pool);
 #endif
 	/* FS&K */
 	random_fortuna_reseed_internal(s, i);
 	RANDOM_RESEED_UNLOCK();
 
 	/* Clean up and secure */
 	explicit_bzero(s, sizeof(s));
 	explicit_bzero(temp, sizeof(temp));
 }
 
 /*-
  * FS&K - RandomData() (Part 2)
  * Main read from Fortuna, continued. May be called multiple times after
  * the random_fortuna_pre_read() above.
  * The supplied buf MUST be a multiple of RANDOM_BLOCKSIZE in size.
  * Lots of code presumes this for efficiency, both here and in other
  * routines. You are NOT allowed to break this!
  */
 void
 random_fortuna_read(uint8_t *buf, u_int bytecount)
 {
 
 	KASSERT((bytecount % RANDOM_BLOCKSIZE) == 0, ("%s(): bytecount (= %d) must be a multiple of %d", __func__, bytecount, RANDOM_BLOCKSIZE ));
 	RANDOM_RESEED_LOCK();
 	random_fortuna_genrandom(buf, bytecount);
 	RANDOM_RESEED_UNLOCK();
 }
 
+#ifdef _KERNEL
+static bool block_seeded_status = false;
+SYSCTL_BOOL(_kern_random, OID_AUTO, block_seeded_status, CTLFLAG_RWTUN,
+    &block_seeded_status, 0,
+    "If non-zero, pretend Fortuna is in an unseeded state.  By setting "
+    "this as a tunable, boot can be tested as if the random device is "
+    "unavailable.");
+#endif
+
 bool
 random_fortuna_seeded(void)
 {
 
 #ifdef _KERNEL
-	/* When set, act as if we are not seeded. */
-	KFAIL_POINT_CODE(DEBUG_FP, random_fortuna_seeded, {
-		if (RETURN_VALUE != 0)
-			fortuna_state.fs_counter = UINT128_ZERO;
-	});
+	if (block_seeded_status)
+		return (false);
 #endif
 
 	return (!uint128_is_zero(fortuna_state.fs_counter));
 }
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index c040649c17b2..3cd82571ebc0 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -1,542 +1,537 @@
 /*-
  * Copyright (c) 2017 Oliver Pinter
  * Copyright (c) 2017 W. Dean Freeman
  * Copyright (c) 2000-2015 Mark R V Murray
  * Copyright (c) 2013 Arthur Mesh
  * Copyright (c) 2004 Robert N. M. Watson
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/conf.h>
 #include <sys/eventhandler.h>
 #include <sys/hash.h>
 #include <sys/kernel.h>
 #include <sys/kthread.h>
 #include <sys/linker.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/random.h>
 #include <sys/sbuf.h>
 #include <sys/sysctl.h>
 #include <sys/unistd.h>
 
 #if defined(RANDOM_LOADABLE)
 #include <sys/lock.h>
 #include <sys/sx.h>
 #endif
 
 #include <machine/atomic.h>
 #include <machine/cpu.h>
 
 #include <crypto/rijndael/rijndael-api-fst.h>
 #include <crypto/sha2/sha256.h>
 
 #include <dev/random/hash.h>
 #include <dev/random/randomdev.h>
 #include <dev/random/random_harvestq.h>
 
 static void random_kthread(void);
 static void random_sources_feed(void);
 
 static u_int read_rate;
 
 /* List for the dynamic sysctls */
 static struct sysctl_ctx_list random_clist;
 
 /*
  * How many events to queue up. We create this many items in
  * an 'empty' queue, then transfer them to the 'harvest' queue with
  * supplied junk. When used, they are transferred back to the
  * 'empty' queue.
  */
 #define	RANDOM_RING_MAX		1024
 #define	RANDOM_ACCUM_MAX	8
 
 /* 1 to let the kernel thread run, 0 to terminate, -1 to mark completion */
 volatile int random_kthread_control;
 
 
 /* Allow the sysadmin to select the broad category of
  * entropy types to harvest.
  */
 __read_frequently u_int hc_source_mask;
 
 /*
  * Put all the harvest queue context stuff in one place.
  * this make is a bit easier to lock and protect.
  */
 static struct harvest_context {
 	/* The harvest mutex protects all of harvest_context and
 	 * the related data.
 	 */
 	struct mtx hc_mtx;
 	/* Round-robin destination cache. */
 	u_int hc_destination[ENTROPYSOURCE];
 	/* The context of the kernel thread processing harvested entropy */
 	struct proc *hc_kthread_proc;
 	/*
 	 * Lockless ring buffer holding entropy events
 	 * If ring.in == ring.out,
 	 *     the buffer is empty.
 	 * If ring.in != ring.out,
 	 *     the buffer contains harvested entropy.
 	 * If (ring.in + 1) == ring.out (mod RANDOM_RING_MAX),
 	 *     the buffer is full.
 	 *
 	 * NOTE: ring.in points to the last added element,
 	 * and ring.out points to the last consumed element.
 	 *
 	 * The ring.in variable needs locking as there are multiple
 	 * sources to the ring. Only the sources may change ring.in,
 	 * but the consumer may examine it.
 	 *
 	 * The ring.out variable does not need locking as there is
 	 * only one consumer. Only the consumer may change ring.out,
 	 * but the sources may examine it.
 	 */
 	struct entropy_ring {
 		struct harvest_event ring[RANDOM_RING_MAX];
 		volatile u_int in;
 		volatile u_int out;
 	} hc_entropy_ring;
 	struct fast_entropy_accumulator {
 		volatile u_int pos;
 		uint32_t buf[RANDOM_ACCUM_MAX];
 	} hc_entropy_fast_accumulator;
 } harvest_context;
 
 static struct kproc_desc random_proc_kp = {
 	"rand_harvestq",
 	random_kthread,
 	&harvest_context.hc_kthread_proc,
 };
 
 /* Pass the given event straight through to Fortuna/Whatever. */
 static __inline void
 random_harvestq_fast_process_event(struct harvest_event *event)
 {
 #if defined(RANDOM_LOADABLE)
 	RANDOM_CONFIG_S_LOCK();
 	if (p_random_alg_context)
 #endif
 	p_random_alg_context->ra_event_processor(event);
 #if defined(RANDOM_LOADABLE)
 	RANDOM_CONFIG_S_UNLOCK();
 #endif
 }
 
 static void
 random_kthread(void)
 {
         u_int maxloop, ring_out, i;
 
 	/*
 	 * Locking is not needed as this is the only place we modify ring.out, and
 	 * we only examine ring.in without changing it. Both of these are volatile,
 	 * and this is a unique thread.
 	 */
 	for (random_kthread_control = 1; random_kthread_control;) {
 		/* Deal with events, if any. Restrict the number we do in one go. */
 		maxloop = RANDOM_RING_MAX;
 		while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) {
 			ring_out = (harvest_context.hc_entropy_ring.out + 1)%RANDOM_RING_MAX;
 			random_harvestq_fast_process_event(harvest_context.hc_entropy_ring.ring + ring_out);
 			harvest_context.hc_entropy_ring.out = ring_out;
 			if (!--maxloop)
 				break;
 		}
 		random_sources_feed();
 		/* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */
 		for (i = 0; i < RANDOM_ACCUM_MAX; i++) {
 			if (harvest_context.hc_entropy_fast_accumulator.buf[i]) {
 				random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA);
 				harvest_context.hc_entropy_fast_accumulator.buf[i] = 0;
 			}
 		}
 		/* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */
 		tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1));
 	}
 	random_kthread_control = -1;
 	wakeup(&harvest_context.hc_kthread_proc);
 	kproc_exit(0);
 	/* NOTREACHED */
 }
 /* This happens well after SI_SUB_RANDOM */
 SYSINIT(random_device_h_proc, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, kproc_start,
     &random_proc_kp);
 
 /*
  * Run through all fast sources reading entropy for the given
  * number of rounds, which should be a multiple of the number
  * of entropy accumulation pools in use; it is 32 for Fortuna.
  */
 static void
 random_sources_feed(void)
 {
 	uint32_t entropy[HARVESTSIZE];
 	struct random_sources *rrs;
 	u_int i, n, local_read_rate;
 
 	/*
 	 * Step over all of live entropy sources, and feed their output
 	 * to the system-wide RNG.
 	 */
 #if defined(RANDOM_LOADABLE)
 	RANDOM_CONFIG_S_LOCK();
 	if (p_random_alg_context) {
 	/* It's an indenting error. Yeah, Yeah. */
 #endif
 	local_read_rate = atomic_readandclear_32(&read_rate);
 	/* Perform at least one read per round */
 	local_read_rate = MAX(local_read_rate, 1);
 	/* But not exceeding RANDOM_KEYSIZE_WORDS */
 	local_read_rate = MIN(local_read_rate, RANDOM_KEYSIZE_WORDS);
 	LIST_FOREACH(rrs, &source_list, rrs_entries) {
 		for (i = 0; i < p_random_alg_context->ra_poolcount*local_read_rate; i++) {
 			n = rrs->rrs_source->rs_read(entropy, sizeof(entropy));
 			KASSERT((n <= sizeof(entropy)), ("%s: rs_read returned too much data (%u > %zu)", __func__, n, sizeof(entropy)));
 			/* It would appear that in some circumstances (e.g. virtualisation),
 			 * the underlying hardware entropy source might not always return
 			 * random numbers. Accept this but make a noise. If too much happens,
 			 * can that source be trusted?
 			 */
 			if (n == 0) {
 				printf("%s: rs_read for hardware device '%s' returned no entropy.\n", __func__, rrs->rrs_source->rs_ident);
 				continue;
 			}
 			random_harvest_direct(entropy, n, rrs->rrs_source->rs_source);
 		}
 	}
 	explicit_bzero(entropy, sizeof(entropy));
 #if defined(RANDOM_LOADABLE)
 	}
 	RANDOM_CONFIG_S_UNLOCK();
 #endif
 }
 
 void
 read_rate_increment(u_int chunk)
 {
 
 	atomic_add_32(&read_rate, chunk);
 }
 
 /* ARGSUSED */
 static int
 random_check_uint_harvestmask(SYSCTL_HANDLER_ARGS)
 {
 	int error;
 	u_int value, orig_value;
 
 	orig_value = value = hc_source_mask;
 	error = sysctl_handle_int(oidp, &value, 0, req);
 	if (error != 0 || req->newptr == NULL)
 		return (error);
 
 	if (flsl(value) > ENTROPYSOURCE)
 		return (EINVAL);
 
 	/*
 	 * Disallow userspace modification of pure entropy sources.
 	 */
 	hc_source_mask = (value & ~RANDOM_HARVEST_PURE_MASK) |
 	    (orig_value & RANDOM_HARVEST_PURE_MASK);
 	return (0);
 }
 
 /* ARGSUSED */
 static int
 random_print_harvestmask(SYSCTL_HANDLER_ARGS)
 {
 	struct sbuf sbuf;
 	int error, i;
 
 	error = sysctl_wire_old_buffer(req, 0);
 	if (error == 0) {
 		sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
 		for (i = ENTROPYSOURCE - 1; i >= 0; i--)
 			sbuf_cat(&sbuf, (hc_source_mask & (1 << i)) ? "1" : "0");
 		error = sbuf_finish(&sbuf);
 		sbuf_delete(&sbuf);
 	}
 	return (error);
 }
 
 static const char *random_source_descr[ENTROPYSOURCE] = {
 	[RANDOM_CACHED] = "CACHED",
 	[RANDOM_ATTACH] = "ATTACH",
 	[RANDOM_KEYBOARD] = "KEYBOARD",
 	[RANDOM_MOUSE] = "MOUSE",
 	[RANDOM_NET_TUN] = "NET_TUN",
 	[RANDOM_NET_ETHER] = "NET_ETHER",
 	[RANDOM_NET_NG] = "NET_NG",
 	[RANDOM_INTERRUPT] = "INTERRUPT",
 	[RANDOM_SWI] = "SWI",
 	[RANDOM_FS_ATIME] = "FS_ATIME",
 	[RANDOM_UMA] = "UMA", /* ENVIRONMENTAL_END */
 	[RANDOM_PURE_OCTEON] = "PURE_OCTEON", /* PURE_START */
 	[RANDOM_PURE_SAFE] = "PURE_SAFE",
 	[RANDOM_PURE_GLXSB] = "PURE_GLXSB",
 	[RANDOM_PURE_UBSEC] = "PURE_UBSEC",
 	[RANDOM_PURE_HIFN] = "PURE_HIFN",
 	[RANDOM_PURE_RDRAND] = "PURE_RDRAND",
 	[RANDOM_PURE_NEHEMIAH] = "PURE_NEHEMIAH",
 	[RANDOM_PURE_RNDTEST] = "PURE_RNDTEST",
 	[RANDOM_PURE_VIRTIO] = "PURE_VIRTIO",
 	[RANDOM_PURE_BROADCOM] = "PURE_BROADCOM",
 	[RANDOM_PURE_CCP] = "PURE_CCP",
 	[RANDOM_PURE_DARN] = "PURE_DARN",
 	[RANDOM_PURE_TPM] = "PURE_TPM",
 	/* "ENTROPYSOURCE" */
 };
 
 /* ARGSUSED */
 static int
 random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS)
 {
 	struct sbuf sbuf;
 	int error, i;
 	bool first;
 
 	first = true;
 	error = sysctl_wire_old_buffer(req, 0);
 	if (error == 0) {
 		sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
 		for (i = ENTROPYSOURCE - 1; i >= 0; i--) {
 			if (i >= RANDOM_PURE_START &&
 			    (hc_source_mask & (1 << i)) == 0)
 				continue;
 			if (!first)
 				sbuf_cat(&sbuf, ",");
 			sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "[" : "");
 			sbuf_cat(&sbuf, random_source_descr[i]);
 			sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "]" : "");
 			first = false;
 		}
 		error = sbuf_finish(&sbuf);
 		sbuf_delete(&sbuf);
 	}
 	return (error);
 }
 
 /* ARGSUSED */
 static void
 random_harvestq_init(void *unused __unused)
 {
 	struct sysctl_oid *random_sys_o;
 
 	random_sys_o = SYSCTL_ADD_NODE(&random_clist,
 	    SYSCTL_STATIC_CHILDREN(_kern_random),
 	    OID_AUTO, "harvest", CTLFLAG_RW, 0,
 	    "Entropy Device Parameters");
 	hc_source_mask = RANDOM_HARVEST_EVERYTHING_MASK;
 	SYSCTL_ADD_PROC(&random_clist,
 	    SYSCTL_CHILDREN(random_sys_o),
 	    OID_AUTO, "mask", CTLTYPE_UINT | CTLFLAG_RW,
 	    NULL, 0, random_check_uint_harvestmask, "IU",
 	    "Entropy harvesting mask");
 	SYSCTL_ADD_PROC(&random_clist,
 	    SYSCTL_CHILDREN(random_sys_o),
 	    OID_AUTO, "mask_bin", CTLTYPE_STRING | CTLFLAG_RD,
 	    NULL, 0, random_print_harvestmask, "A", "Entropy harvesting mask (printable)");
 	SYSCTL_ADD_PROC(&random_clist,
 	    SYSCTL_CHILDREN(random_sys_o),
 	    OID_AUTO, "mask_symbolic", CTLTYPE_STRING | CTLFLAG_RD,
 	    NULL, 0, random_print_harvestmask_symbolic, "A", "Entropy harvesting mask (symbolic)");
 	RANDOM_HARVEST_INIT_LOCK();
 	harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0;
 }
 SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL);
 
 /*
  * This is used to prime the RNG by grabbing any early random stuff
  * known to the kernel, and inserting it directly into the hashing
  * module, currently Fortuna.
  */
 /* ARGSUSED */
 static void
 random_harvestq_prime(void *unused __unused)
 {
 	struct harvest_event event;
 	size_t count, size, i;
 	uint8_t *keyfile, *data;
 
 	/*
 	 * Get entropy that may have been preloaded by loader(8)
 	 * and use it to pre-charge the entropy harvest queue.
 	 */
 	keyfile = preload_search_by_type(RANDOM_CACHED_BOOT_ENTROPY_MODULE);
 #ifndef NO_BACKWARD_COMPATIBILITY
 	if (keyfile == NULL)
 	    keyfile = preload_search_by_type(RANDOM_LEGACY_BOOT_ENTROPY_MODULE);
 #endif
 	if (keyfile != NULL) {
 		data = preload_fetch_addr(keyfile);
 		size = preload_fetch_size(keyfile);
-		/* skip the first bit of the stash so others like arc4 can also have some. */
-		if (size > RANDOM_CACHED_SKIP_START) {
-			data += RANDOM_CACHED_SKIP_START;
-			size -= RANDOM_CACHED_SKIP_START;
-		}
 		/* Trim the size. If the admin has a file with a funny size, we lose some. Tough. */
 		size -= (size % sizeof(event.he_entropy));
 		if (data != NULL && size != 0) {
 			for (i = 0; i < size; i += sizeof(event.he_entropy)) {
 				count = sizeof(event.he_entropy);
 				event.he_somecounter = (uint32_t)get_cyclecount();
 				event.he_size = count;
 				event.he_source = RANDOM_CACHED;
 				event.he_destination =
 				    harvest_context.hc_destination[RANDOM_CACHED]++;
 				memcpy(event.he_entropy, data + i, sizeof(event.he_entropy));
 				random_harvestq_fast_process_event(&event);
 				explicit_bzero(&event, sizeof(event));
 			}
 			explicit_bzero(data, size);
 			if (bootverbose)
 				printf("random: read %zu bytes from preloaded cache\n", size);
 		} else
 			if (bootverbose)
 				printf("random: no preloaded entropy cache\n");
 	}
 }
 SYSINIT(random_device_prime, SI_SUB_RANDOM, SI_ORDER_FOURTH, random_harvestq_prime, NULL);
 
 /* ARGSUSED */
 static void
 random_harvestq_deinit(void *unused __unused)
 {
 
 	/* Command the hash/reseed thread to end and wait for it to finish */
 	random_kthread_control = 0;
 	while (random_kthread_control >= 0)
 		tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", hz/5);
 	sysctl_ctx_free(&random_clist);
 }
 SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL);
 
 /*-
  * Entropy harvesting queue routine.
  *
  * This is supposed to be fast; do not do anything slow in here!
  * It is also illegal (and morally reprehensible) to insert any
  * high-rate data here. "High-rate" is defined as a data source
  * that will usually cause lots of failures of the "Lockless read"
  * check a few lines below. This includes the "always-on" sources
  * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources.
  */
 /* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
  * counters are built in, but on older hardware it will do a real time clock
  * read which can be quite expensive.
  */
 void
 random_harvest_queue_(const void *entropy, u_int size, enum random_entropy_source origin)
 {
 	struct harvest_event *event;
 	u_int ring_in;
 
 	KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
 	RANDOM_HARVEST_LOCK();
 	ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX;
 	if (ring_in != harvest_context.hc_entropy_ring.out) {
 		/* The ring is not full */
 		event = harvest_context.hc_entropy_ring.ring + ring_in;
 		event->he_somecounter = (uint32_t)get_cyclecount();
 		event->he_source = origin;
 		event->he_destination = harvest_context.hc_destination[origin]++;
 		if (size <= sizeof(event->he_entropy)) {
 			event->he_size = size;
 			memcpy(event->he_entropy, entropy, size);
 		}
 		else {
 			/* Big event, so squash it */
 			event->he_size = sizeof(event->he_entropy[0]);
 			event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event);
 		}
 		harvest_context.hc_entropy_ring.in = ring_in;
 	}
 	RANDOM_HARVEST_UNLOCK();
 }
 
 /*-
  * Entropy harvesting fast routine.
  *
  * This is supposed to be very fast; do not do anything slow in here!
  * This is the right place for high-rate harvested data.
  */
 void
 random_harvest_fast_(const void *entropy, u_int size)
 {
 	u_int pos;
 
 	pos = harvest_context.hc_entropy_fast_accumulator.pos;
 	harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, size, (uint32_t)get_cyclecount());
 	harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX;
 }
 
 /*-
  * Entropy harvesting direct routine.
  *
  * This is not supposed to be fast, but will only be used during
  * (e.g.) booting when initial entropy is being gathered.
  */
 void
 random_harvest_direct_(const void *entropy, u_int size, enum random_entropy_source origin)
 {
 	struct harvest_event event;
 
 	KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
 	size = MIN(size, sizeof(event.he_entropy));
 	event.he_somecounter = (uint32_t)get_cyclecount();
 	event.he_size = size;
 	event.he_source = origin;
 	event.he_destination = harvest_context.hc_destination[origin]++;
 	memcpy(event.he_entropy, entropy, size);
 	random_harvestq_fast_process_event(&event);
 	explicit_bzero(&event, sizeof(event));
 }
 
 void
 random_harvest_register_source(enum random_entropy_source source)
 {
 
 	hc_source_mask |= (1 << source);
 }
 
 void
 random_harvest_deregister_source(enum random_entropy_source source)
 {
 
 	hc_source_mask &= ~(1 << source);
 }
 
 MODULE_VERSION(random_harvestq, 1);
diff --git a/sys/dev/random/random_infra.c b/sys/dev/random/random_infra.c
index d31b84b24582..324c40dcecd4 100644
--- a/sys/dev/random/random_infra.c
+++ b/sys/dev/random/random_infra.c
@@ -1,128 +1,132 @@
 /*-
  * Copyright (c) 2015 Mark R V Murray
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/random.h>
 #include <sys/sysctl.h>
 
 #if defined(RANDOM_LOADABLE)
 #include <sys/lock.h>
 #include <sys/sx.h>
 #endif
 
 #include <dev/random/randomdev.h>
 
 /* Set up the sysctl root node for the entropy device */
 SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator");
 
 MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
 
 struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
 
 #if defined(RANDOM_LOADABLE)
 struct random_algorithm *p_random_alg_context = NULL;
 #else /* !defined(RANDOM_LOADABLE) */
 struct random_algorithm *p_random_alg_context = &random_alg_context;
 #endif /* defined(RANDOM_LOADABLE) */
 
 #if defined(RANDOM_LOADABLE)
 
+static void
+null_read_random(void *dummy __unused, u_int dummy2 __unused)
+{
+	panic("%s: no random module is loaded", __func__);
+}
+
 struct random_readers {
 	int	(*read_random_uio)(struct uio *, bool);
-	u_int	(*read_random)(void *, u_int);
+	void	(*read_random)(void *, u_int);
 } random_reader_context = {
 	(int (*)(struct uio *, bool))nullop,
-	(u_int (*)(void *, u_int))nullop,
+	null_read_random,
 };
 
 struct sx randomdev_config_lock;
 
 static void
 random_infra_sysinit(void *dummy __unused)
 {
 
 	RANDOM_CONFIG_INIT_LOCK();
 }
 SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL);
 
 void
-random_infra_init(int (*p_random_read_uio)(struct uio *, bool), u_int (*p_random_read)(void *, u_int))
+random_infra_init(int (*p_random_read_uio)(struct uio *, bool), void (*p_random_read)(void *, u_int))
 {
 
 	RANDOM_CONFIG_X_LOCK();
 	random_reader_context.read_random_uio = p_random_read_uio;
 	random_reader_context.read_random = p_random_read;
 	RANDOM_CONFIG_X_UNLOCK();
 }
 
 void
 random_infra_uninit(void)
 {
 
 	RANDOM_CONFIG_X_LOCK();
 	random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop;
-	random_reader_context.read_random = (u_int (*)(void *, u_int))nullop;
+	random_reader_context.read_random = null_read_random;
 	RANDOM_CONFIG_X_UNLOCK();
 }
 
 static void
 random_infra_sysuninit(void *dummy __unused)
 {
 
 	RANDOM_CONFIG_DEINIT_LOCK();
 }
 SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysuninit, NULL);
 
 int
 read_random_uio(struct uio *uio, bool nonblock)
 {
 	int retval;
 
 	RANDOM_CONFIG_S_LOCK();
 	retval = random_reader_context.read_random_uio(uio, nonblock);
 	RANDOM_CONFIG_S_UNLOCK();
 	return (retval);
 }
 
-u_int
+void
 read_random(void *buf, u_int len)
 {
-	u_int retval;
 
 	RANDOM_CONFIG_S_LOCK();
-	retval = random_reader_context.read_random(buf, len);
+	random_reader_context.read_random(buf, len);
 	RANDOM_CONFIG_S_UNLOCK();
-	return (retval);
 }
 
 #endif /* defined(RANDOM_LOADABLE) */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index 94bd2f1a4147..19a73b28151a 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -1,429 +1,464 @@
 /*-
  * Copyright (c) 2017 Oliver Pinter
  * Copyright (c) 2000-2015 Mark R V Murray
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/filio.h>
 #include <sys/kernel.h>
 #include <sys/kthread.h>
 #include <sys/lock.h>
 #include <sys/module.h>
 #include <sys/malloc.h>
 #include <sys/poll.h>
 #include <sys/proc.h>
 #include <sys/random.h>
 #include <sys/sbuf.h>
 #include <sys/selinfo.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/uio.h>
 #include <sys/unistd.h>
 
 #include <crypto/rijndael/rijndael-api-fst.h>
 #include <crypto/sha2/sha256.h>
 
 #include <dev/random/hash.h>
 #include <dev/random/randomdev.h>
 #include <dev/random/random_harvestq.h>
 
 #define	RANDOM_UNIT	0
 
 #if defined(RANDOM_LOADABLE)
 #define READ_RANDOM_UIO	_read_random_uio
 #define READ_RANDOM	_read_random
 static int READ_RANDOM_UIO(struct uio *, bool);
-static u_int READ_RANDOM(void *, u_int);
+static void READ_RANDOM(void *, u_int);
 #else
 #define READ_RANDOM_UIO	read_random_uio
 #define READ_RANDOM	read_random
 #endif
 
 static d_read_t randomdev_read;
 static d_write_t randomdev_write;
 static d_poll_t randomdev_poll;
 static d_ioctl_t randomdev_ioctl;
 
 static struct cdevsw random_cdevsw = {
 	.d_name = "random",
 	.d_version = D_VERSION,
 	.d_read = randomdev_read,
 	.d_write = randomdev_write,
 	.d_poll = randomdev_poll,
 	.d_ioctl = randomdev_ioctl,
 };
 
 /* For use with make_dev(9)/destroy_dev(9). */
 static struct cdev *random_dev;
 
 static void
 random_alg_context_ra_init_alg(void *data)
 {
 
 	p_random_alg_context = &random_alg_context;
 	p_random_alg_context->ra_init_alg(data);
 #if defined(RANDOM_LOADABLE)
 	random_infra_init(READ_RANDOM_UIO, READ_RANDOM);
 #endif
 }
 
 static void
 random_alg_context_ra_deinit_alg(void *data)
 {
 
 #if defined(RANDOM_LOADABLE)
 	random_infra_uninit();
 #endif
 	p_random_alg_context->ra_deinit_alg(data);
 	p_random_alg_context = NULL;
 }
 
 SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL);
 SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL);
 
 static struct selinfo rsel;
 
 /*
  * This is the read uio(9) interface for random(4).
  */
 /* ARGSUSED */
 static int
 randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags)
 {
 
 	return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0));
 }
 
+/*
+ * If the random device is not seeded, blocks until it is seeded.
+ *
+ * Returns zero when the random device is seeded.
+ *
+ * If the 'interruptible' parameter is true, and the device is unseeded, this
+ * routine may be interrupted.  If interrupted, it will return either ERESTART
+ * or EINTR.
+ */
+#define SEEDWAIT_INTERRUPTIBLE		true
+#define SEEDWAIT_UNINTERRUPTIBLE	false
+static int
+randomdev_wait_until_seeded(bool interruptible)
+{
+	int error, spamcount, slpflags;
+
+	slpflags = interruptible ? PCATCH : 0;
+
+	error = 0;
+	spamcount = 0;
+	while (!p_random_alg_context->ra_seeded()) {
+		/* keep tapping away at the pre-read until we seed/unblock. */
+		p_random_alg_context->ra_pre_read();
+		/* Only bother the console every 10 seconds or so */
+		if (spamcount == 0)
+			printf("random: %s unblock wait\n", __func__);
+		spamcount = (spamcount + 1) % 100;
+		error = tsleep(&random_alg_context, slpflags, "randseed",
+		    hz / 10);
+		if (error == ERESTART || error == EINTR) {
+			KASSERT(interruptible,
+			    ("unexpected wake of non-interruptible sleep"));
+			break;
+		}
+		/* Squash tsleep timeout condition */
+		if (error == EWOULDBLOCK)
+			error = 0;
+		KASSERT(error == 0, ("unexpected tsleep error %d", error));
+	}
+	return (error);
+}
+
 int
 READ_RANDOM_UIO(struct uio *uio, bool nonblock)
 {
 	uint8_t *random_buf;
-	int error, spamcount;
+	int error;
 	ssize_t read_len, total_read, c;
 	/* 16 MiB takes about 0.08 s CPU time on my 2017 AMD Zen CPU */
 #define SIGCHK_PERIOD (16 * 1024 * 1024)
 	const size_t sigchk_period = SIGCHK_PERIOD;
 
 	CTASSERT(SIGCHK_PERIOD % PAGE_SIZE == 0);
 #undef SIGCHK_PERIOD
 
 	random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
 	p_random_alg_context->ra_pre_read();
 	error = 0;
-	spamcount = 0;
 	/* (Un)Blocking logic */
-	while (!p_random_alg_context->ra_seeded()) {
-		if (nonblock) {
+	if (!p_random_alg_context->ra_seeded()) {
+		if (nonblock)
 			error = EWOULDBLOCK;
-			break;
-		}
-		/* keep tapping away at the pre-read until we seed/unblock. */
-		p_random_alg_context->ra_pre_read();
-		/* Only bother the console every 10 seconds or so */
-		if (spamcount == 0)
-			printf("random: %s unblock wait\n", __func__);
-		spamcount = (spamcount + 1)%100;
-		error = tsleep(&random_alg_context, PCATCH, "randseed", hz/10);
-		if (error == ERESTART || error == EINTR)
-			break;
-		/* Squash tsleep timeout condition */
-		if (error == EWOULDBLOCK)
-			error = 0;
-		KASSERT(error == 0, ("unexpected tsleep error %d", error));
+		else
+			error = randomdev_wait_until_seeded(
+			    SEEDWAIT_INTERRUPTIBLE);
 	}
 	if (error == 0) {
 		read_rate_increment((uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t));
 		total_read = 0;
 		while (uio->uio_resid && !error) {
 			read_len = uio->uio_resid;
 			/*
 			 * Belt-and-braces.
 			 * Round up the read length to a crypto block size multiple,
 			 * which is what the underlying generator is expecting.
 			 * See the random_buf size requirements in the Fortuna code.
 			 */
 			read_len = roundup(read_len, RANDOM_BLOCKSIZE);
 			/* Work in chunks page-sized or less */
 			read_len = MIN(read_len, PAGE_SIZE);
 			p_random_alg_context->ra_read(random_buf, read_len);
 			c = MIN(uio->uio_resid, read_len);
 			/*
 			 * uiomove() may yield the CPU before each 'c' bytes
 			 * (up to PAGE_SIZE) are copied out.
 			 */
 			error = uiomove(random_buf, c, uio);
 			total_read += c;
 			/*
 			 * Poll for signals every few MBs to avoid very long
 			 * uninterruptible syscalls.
 			 */
 			if (error == 0 && uio->uio_resid != 0 &&
 			    total_read % sigchk_period == 0) {
 				error = tsleep_sbt(&random_alg_context, PCATCH,
 				    "randrd", SBT_1NS, 0, C_HARDCLOCK);
 				/* Squash tsleep timeout condition */
 				if (error == EWOULDBLOCK)
 					error = 0;
 			}
 		}
 		if (error == ERESTART || error == EINTR)
 			error = 0;
 	}
 	free(random_buf, M_ENTROPY);
 	return (error);
 }
 
 /*-
  * Kernel API version of read_random().
  * This is similar to random_alg_read(),
  * except it doesn't interface with uio(9).
  * It cannot assumed that random_buf is a multiple of
  * RANDOM_BLOCKSIZE bytes.
  */
-u_int
+void
 READ_RANDOM(void *random_buf, u_int len)
 {
-	u_int read_len;
-	uint8_t local_buf[len + RANDOM_BLOCKSIZE];
+	u_int read_directly_len;
 
 	KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__));
 	p_random_alg_context->ra_pre_read();
-	/* (Un)Blocking logic; if not seeded, return nothing. */
-	if (p_random_alg_context->ra_seeded()) {
-		read_rate_increment((len + sizeof(uint32_t))/sizeof(uint32_t));
-		if (len > 0) {
-			/*
-			 * Belt-and-braces.
-			 * Round up the read length to a crypto block size multiple,
-			 * which is what the underlying generator is expecting.
-			 */
-			read_len = roundup(len, RANDOM_BLOCKSIZE);
-			p_random_alg_context->ra_read(local_buf, read_len);
-			memcpy(random_buf, local_buf, len);
-		}
-	} else
-		len = 0;
-	return (len);
+	/* (Un)Blocking logic */
+	if (!p_random_alg_context->ra_seeded())
+		(void)randomdev_wait_until_seeded(SEEDWAIT_UNINTERRUPTIBLE);
+	read_rate_increment(roundup2(len, sizeof(uint32_t)));
+	if (len == 0)
+		return;
+	/*
+	 * The underlying generator expects multiples of
+	 * RANDOM_BLOCKSIZE.
+	 */
+	read_directly_len = rounddown(len, RANDOM_BLOCKSIZE);
+	if (read_directly_len > 0)
+		p_random_alg_context->ra_read(random_buf, read_directly_len);
+	if (read_directly_len < len) {
+		uint8_t remainder_buf[RANDOM_BLOCKSIZE];
+
+		p_random_alg_context->ra_read(remainder_buf,
+		    sizeof(remainder_buf));
+		memcpy((char *)random_buf + read_directly_len, remainder_buf,
+		    len - read_directly_len);
+
+		explicit_bzero(remainder_buf, sizeof(remainder_buf));
+	}
 }
 
 static __inline void
 randomdev_accumulate(uint8_t *buf, u_int count)
 {
 	static u_int destination = 0;
 	static struct harvest_event event;
 	static struct randomdev_hash hash;
 	static uint32_t entropy_data[RANDOM_KEYSIZE_WORDS];
 	uint32_t timestamp;
 	int i;
 
 	/* Extra timing here is helpful to scrape scheduler jitter entropy */
 	randomdev_hash_init(&hash);
 	timestamp = (uint32_t)get_cyclecount();
 	randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
 	randomdev_hash_iterate(&hash, buf, count);
 	timestamp = (uint32_t)get_cyclecount();
 	randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
 	randomdev_hash_finish(&hash, entropy_data);
 	explicit_bzero(&hash, sizeof(hash));
 	for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
 		event.he_somecounter = (uint32_t)get_cyclecount();
 		event.he_size = sizeof(event.he_entropy);
 		event.he_source = RANDOM_CACHED;
 		event.he_destination = destination++; /* Harmless cheating */
 		memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy));
 		p_random_alg_context->ra_event_processor(&event);
 	}
 	explicit_bzero(entropy_data, sizeof(entropy_data));
 }
 
 /* ARGSUSED */
 static int
 randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
 {
 	uint8_t *random_buf;
 	int c, error = 0;
 	ssize_t nbytes;
 
 	random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
 	nbytes = uio->uio_resid;
 	while (uio->uio_resid > 0 && error == 0) {
 		c = MIN(uio->uio_resid, PAGE_SIZE);
 		error = uiomove(random_buf, c, uio);
 		if (error)
 			break;
 		randomdev_accumulate(random_buf, c);
 		tsleep(&random_alg_context, 0, "randwr", hz/10);
 	}
 	if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR))
 		/* Partial write, not error. */
 		error = 0;
 	free(random_buf, M_ENTROPY);
 	return (error);
 }
 
 /* ARGSUSED */
 static int
 randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
 {
 
 	if (events & (POLLIN | POLLRDNORM)) {
 		if (p_random_alg_context->ra_seeded())
 			events &= (POLLIN | POLLRDNORM);
 		else
 			selrecord(td, &rsel);
 	}
 	return (events);
 }
 
 /* This will be called by the entropy processor when it seeds itself and becomes secure */
 void
 randomdev_unblock(void)
 {
 
 	selwakeuppri(&rsel, PUSER);
 	wakeup(&random_alg_context);
 	printf("random: unblocking device.\n");
 	/* Do random(9) a favour while we are about it. */
 	(void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE);
 }
 
 /* ARGSUSED */
 static int
 randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
     int flags __unused, struct thread *td __unused)
 {
 	int error = 0;
 
 	switch (cmd) {
 		/* Really handled in upper layer */
 	case FIOASYNC:
 	case FIONBIO:
 		break;
 	default:
 		error = ENOTTY;
 	}
 
 	return (error);
 }
 
 void
 random_source_register(struct random_source *rsource)
 {
 	struct random_sources *rrs;
 
 	KASSERT(rsource != NULL, ("invalid input to %s", __func__));
 
 	rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK);
 	rrs->rrs_source = rsource;
 
 	random_harvest_register_source(rsource->rs_source);
 
 	printf("random: registering fast source %s\n", rsource->rs_ident);
 	LIST_INSERT_HEAD(&source_list, rrs, rrs_entries);
 }
 
 void
 random_source_deregister(struct random_source *rsource)
 {
 	struct random_sources *rrs = NULL;
 
 	KASSERT(rsource != NULL, ("invalid input to %s", __func__));
 
 	random_harvest_deregister_source(rsource->rs_source);
 
 	LIST_FOREACH(rrs, &source_list, rrs_entries)
 		if (rrs->rrs_source == rsource) {
 			LIST_REMOVE(rrs, rrs_entries);
 			break;
 		}
 	if (rrs != NULL)
 		free(rrs, M_ENTROPY);
 }
 
 static int
 random_source_handler(SYSCTL_HANDLER_ARGS)
 {
 	struct random_sources *rrs;
 	struct sbuf sbuf;
 	int error, count;
 
 	sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
 	count = 0;
 	LIST_FOREACH(rrs, &source_list, rrs_entries) {
 		sbuf_cat(&sbuf, (count++ ? ",'" : "'"));
 		sbuf_cat(&sbuf, rrs->rrs_source->rs_ident);
 		sbuf_cat(&sbuf, "'");
 	}
 	error = sbuf_finish(&sbuf);
 	sbuf_delete(&sbuf);
 	return (error);
 }
 SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
 	    NULL, 0, random_source_handler, "A",
 	    "List of active fast entropy sources.");
 
 /* ARGSUSED */
 static int
 randomdev_modevent(module_t mod __unused, int type, void *data __unused)
 {
 	int error = 0;
 
 	switch (type) {
 	case MOD_LOAD:
 		printf("random: entropy device external interface\n");
 		random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
 		    RANDOM_UNIT, NULL, UID_ROOT, GID_WHEEL, 0644, "random");
 		make_dev_alias(random_dev, "urandom"); /* compatibility */
 		break;
 	case MOD_UNLOAD:
 		destroy_dev(random_dev);
 		break;
 	case MOD_SHUTDOWN:
 		break;
 	default:
 		error = EOPNOTSUPP;
 		break;
 	}
 	return (error);
 }
 
 static moduledata_t randomdev_mod = {
 	"random_device",
 	randomdev_modevent,
 	0
 };
 
 DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
 MODULE_VERSION(random_device, 1);
 MODULE_DEPEND(random_device, crypto, 1, 1, 1);
 MODULE_DEPEND(random_device, random_harvestq, 1, 1, 1);
diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h
index 0f3b359d1f1f..41300f237aaf 100644
--- a/sys/dev/random/randomdev.h
+++ b/sys/dev/random/randomdev.h
@@ -1,129 +1,129 @@
 /*-
  * Copyright (c) 2000-2015 Mark R V Murray
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #ifndef SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
 #define	SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
 
 #ifdef _KERNEL
 
 /* This header contains only those definitions that are global
  * and non algorithm-specific for the entropy processor
  */
 
 #ifdef SYSCTL_DECL	/* from sysctl.h */
 SYSCTL_DECL(_kern_random);
 
 #define	RANDOM_CHECK_UINT(name, min, max)				\
 static int								\
 random_check_uint_##name(SYSCTL_HANDLER_ARGS)				\
 {									\
 	if (oidp->oid_arg1 != NULL) {					\
 		if (*(u_int *)(oidp->oid_arg1) <= (min))		\
 			*(u_int *)(oidp->oid_arg1) = (min);		\
 		else if (*(u_int *)(oidp->oid_arg1) > (max))		\
 			*(u_int *)(oidp->oid_arg1) = (max);		\
 	}								\
 	return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2,	\
 		req));							\
 }
 #endif /* SYSCTL_DECL */
 
 MALLOC_DECLARE(M_ENTROPY);
 
 #endif /* _KERNEL */
 
 struct harvest_event;
 
 typedef void random_alg_init_t(void *);
 typedef void random_alg_deinit_t(void *);
 typedef void random_alg_pre_read_t(void);
 typedef void random_alg_read_t(uint8_t *, u_int);
 typedef bool random_alg_seeded_t(void);
 typedef void random_alg_reseed_t(void);
 typedef void random_alg_eventprocessor_t(struct harvest_event *);
 
 typedef u_int random_source_read_t(void *, u_int);
 
 /*
  * Random Algorithm is a processor of randomness for the kernel
  * and for userland.
  */
 struct random_algorithm {
 	const char			*ra_ident;
 	u_int				 ra_poolcount;
 	void				(*ra_init_alg)(void *);
 	void				(*ra_deinit_alg)(void *);
 	random_alg_pre_read_t		*ra_pre_read;
 	random_alg_read_t		*ra_read;
 	random_alg_seeded_t		*ra_seeded;
 	random_alg_eventprocessor_t	*ra_event_processor;
 };
 
 extern struct random_algorithm random_alg_context, *p_random_alg_context;
 
 #ifdef _KERNEL
 
 /*
  * Random Source is a source of entropy that can provide
  * specified or approximate amount of entropy immediately
  * upon request.
  */
 struct random_source {
 	const char			*rs_ident;
 	enum random_entropy_source	 rs_source;
 	random_source_read_t		*rs_read;
 };
 
 struct random_sources {
 	LIST_ENTRY(random_sources)	 rrs_entries;
 	struct random_source		*rrs_source;
 };
 
 LIST_HEAD(sources_head, random_sources);
 extern struct sources_head source_list;
 
 void random_source_register(struct random_source *);
 void random_source_deregister(struct random_source *);
 
 #if defined(RANDOM_LOADABLE)
 extern struct sx randomdev_config_lock;
 #define	RANDOM_CONFIG_INIT_LOCK(x)	sx_init(&randomdev_config_lock, "configuration change lock")
 #define	RANDOM_CONFIG_X_LOCK(x)		sx_xlock(&randomdev_config_lock)
 #define	RANDOM_CONFIG_X_UNLOCK(x)	sx_xunlock(&randomdev_config_lock)
 #define	RANDOM_CONFIG_S_LOCK(x)		sx_slock(&randomdev_config_lock)
 #define	RANDOM_CONFIG_S_UNLOCK(x)	sx_sunlock(&randomdev_config_lock)
 #define	RANDOM_CONFIG_DEINIT_LOCK(x)	sx_destroy(&randomdev_config_lock)
-void random_infra_init(int (*)(struct uio *, bool), u_int (*)(void *, u_int));
+void random_infra_init(int (*)(struct uio *, bool), void (*)(void *, u_int));
 void random_infra_uninit(void);
 #endif
 
 #endif /* _KERNEL */
 
 void randomdev_unblock(void);
 
 #endif /* SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED */
diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c
index ed44645246d4..fd46419ba8a0 100644
--- a/sys/kern/kern_mib.c
+++ b/sys/kern/kern_mib.c
@@ -1,675 +1,668 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1982, 1986, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Mike Karels at Berkeley Software Design, Inc.
  *
  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
  * project, to make these variables more userfriendly.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include "opt_posix.h"
 #include "opt_config.h"
 
 #include <sys/param.h>
 #include <sys/boot.h>
 #include <sys/jail.h>
 #include <sys/kernel.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/random.h>
 #include <sys/sbuf.h>
 #include <sys/smp.h>
 #include <sys/sx.h>
 #include <sys/vmmeter.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/unistd.h>
 
 SYSCTL_ROOT_NODE(0,	  sysctl, CTLFLAG_RW, 0,
 	"Sysctl internal magic");
 SYSCTL_ROOT_NODE(CTL_KERN,	  kern,   CTLFLAG_RW|CTLFLAG_CAPRD, 0,
 	"High kernel, proc, limits &c");
 SYSCTL_ROOT_NODE(CTL_VM,	  vm,     CTLFLAG_RW, 0,
 	"Virtual memory");
 SYSCTL_ROOT_NODE(CTL_VFS,	  vfs,     CTLFLAG_RW, 0,
 	"File system");
 SYSCTL_ROOT_NODE(CTL_NET,	  net,    CTLFLAG_RW, 0,
 	"Network, (see socket.h)");
 SYSCTL_ROOT_NODE(CTL_DEBUG,  debug,  CTLFLAG_RW, 0,
 	"Debugging");
 SYSCTL_NODE(_debug, OID_AUTO,  sizeof,  CTLFLAG_RW, 0,
 	"Sizeof various things");
 SYSCTL_ROOT_NODE(CTL_HW,	  hw,     CTLFLAG_RW, 0,
 	"hardware");
 SYSCTL_ROOT_NODE(CTL_MACHDEP, machdep, CTLFLAG_RW, 0,
 	"machine dependent");
 SYSCTL_NODE(_machdep, OID_AUTO, mitigations, CTLFLAG_RW, 0,
 	"Machine dependent platform mitigations.");
 SYSCTL_ROOT_NODE(CTL_USER,	  user,   CTLFLAG_RW, 0,
 	"user-level");
 SYSCTL_ROOT_NODE(CTL_P1003_1B,  p1003_1b,   CTLFLAG_RW, 0,
 	"p1003_1b, (see p1003_1b.h)");
 
 SYSCTL_ROOT_NODE(OID_AUTO,  compat, CTLFLAG_RW, 0,
 	"Compatibility code");
 SYSCTL_ROOT_NODE(OID_AUTO, security, CTLFLAG_RW, 0, 
      	"Security");
 #ifdef REGRESSION
 SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0,
      "Regression test MIB");
 #endif
 
 SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE,
     kern_ident, 0, "Kernel identifier");
 
 SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, BSD, "Operating system revision");
 
 SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD|CTLFLAG_MPSAFE,
     version, 0, "Kernel version");
 
 SYSCTL_STRING(_kern, OID_AUTO, compiler_version, CTLFLAG_RD|CTLFLAG_MPSAFE,
     compiler_version, 0, "Version of compiler used to compile kernel");
 
 SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD|CTLFLAG_MPSAFE|
     CTLFLAG_CAPRD, ostype, 0, "Operating system type");
 
 SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
     &maxproc, 0, "Maximum number of processes");
 
 SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW,
     &maxprocperuid, 0, "Maximum processes allowed per userid");
 
 SYSCTL_INT(_kern, OID_AUTO, maxusers, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
     &maxusers, 0, "Hint for kernel tuning");
 
 SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, ARG_MAX, "Maximum bytes of argument to execve(2)");
 
 SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, _POSIX_VERSION, "Version of POSIX attempting to comply to");
 
 SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RDTUN |
     CTLFLAG_NOFETCH | CTLFLAG_CAPRD, &ngroups_max, 0,
     "Maximum number of supplemental groups a user can belong to");
 
 SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, 1, "Whether job control is available");
 
 #ifdef _POSIX_SAVED_IDS
 SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, 1, "Whether saved set-group/user ID is available");
 #else
 SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, 0, "Whether saved set-group/user ID is available");
 #endif
 
 char kernelname[MAXPATHLEN] = PATH_KERNEL;	/* XXX bloat */
 
 SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW | CTLFLAG_MPSAFE,
     kernelname, sizeof kernelname, "Name of kernel file booted");
 
 SYSCTL_INT(_kern, KERN_MAXPHYS, maxphys, CTLFLAG_RD | CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, MAXPHYS, "Maximum block I/O access size");
 
 SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD|CTLFLAG_CAPRD,
     &mp_ncpus, 0, "Number of active CPUs");
 
 SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, BYTE_ORDER, "System byte order");
 
 SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD|CTLFLAG_CAPRD,
     SYSCTL_NULL_INT_PTR, PAGE_SIZE, "System memory page size");
 
 static int
 sysctl_kern_arnd(SYSCTL_HANDLER_ARGS)
 {
 	char buf[256];
 	size_t len;
 
-	/*-
-	 * This is one of the very few legitimate uses of read_random(9).
-	 * Use of arc4random(9) is not recommended as that will ignore
-	 * an unsafe (i.e. unseeded) random(4).
-	 *
-	 * If random(4) is not seeded, then this returns 0, so the
-	 * sysctl will return a zero-length buffer.
-	 */
-	len = read_random(buf, MIN(req->oldlen, sizeof(buf)));
+	len = MIN(req->oldlen, sizeof(buf));
+	read_random(buf, len);
 	return (SYSCTL_OUT(req, buf, len));
 }
 
 SYSCTL_PROC(_kern, KERN_ARND, arandom,
     CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_CAPRD, NULL, 0,
     sysctl_kern_arnd, "", "arc4rand");
 
 static int
 sysctl_hw_physmem(SYSCTL_HANDLER_ARGS)
 {
 	u_long val, p;
 
 	p = SIZE_T_MAX >> PAGE_SHIFT;
 	if (physmem < p)
 		p = physmem;
 	val = ctob(p);
 	return (sysctl_handle_long(oidp, &val, 0, req));
 }
 SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_ULONG | CTLFLAG_RD,
     0, 0, sysctl_hw_physmem, "LU",
     "Amount of physical memory (in bytes)");
 
 static int
 sysctl_hw_realmem(SYSCTL_HANDLER_ARGS)
 {
 	u_long val, p;
 
 	p = SIZE_T_MAX >> PAGE_SHIFT;
 	if (realmem < p)
 		p = realmem;
 	val = ctob(p);
 	return (sysctl_handle_long(oidp, &val, 0, req));
 }
 SYSCTL_PROC(_hw, HW_REALMEM, realmem, CTLTYPE_ULONG | CTLFLAG_RD,
     0, 0, sysctl_hw_realmem, "LU",
     "Amount of memory (in bytes) reported by the firmware");
 
 static int
 sysctl_hw_usermem(SYSCTL_HANDLER_ARGS)
 {
 	u_long val, p, p1;
 
 	p1 = physmem - vm_wire_count();
 	p = SIZE_T_MAX >> PAGE_SHIFT;
 	if (p1 < p)
 		p = p1;
 	val = ctob(p);
 	return (sysctl_handle_long(oidp, &val, 0, req));
 }
 SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_ULONG | CTLFLAG_RD,
     0, 0, sysctl_hw_usermem, "LU",
     "Amount of memory (in bytes) which is not wired");
 
 SYSCTL_LONG(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0,
     "Amount of physical memory (in pages)");
 
 u_long pagesizes[MAXPAGESIZES] = { PAGE_SIZE };
 
 static int
 sysctl_hw_pagesizes(SYSCTL_HANDLER_ARGS)
 {
 	int error;
 	size_t len;
 #ifdef SCTL_MASK32
 	int i;
 	uint32_t pagesizes32[MAXPAGESIZES];
 
 	if (req->flags & SCTL_MASK32) {
 		/*
 		 * Recreate the "pagesizes" array with 32-bit elements.
 		 * Truncate any page size greater than UINT32_MAX to zero,
 		 * which assumes that page sizes are powers of two.
 		 */
 		for (i = 0; i < MAXPAGESIZES; i++)
 			pagesizes32[i] = (uint32_t)pagesizes[i];
 
 		len = sizeof(pagesizes32);
 		if (len > req->oldlen)
 			len = req->oldlen;
 		error = SYSCTL_OUT(req, pagesizes32, len);
 	} else
 #endif
 	{
 		len = sizeof(pagesizes);
 		if (len > req->oldlen)
 			len = req->oldlen;
 		error = SYSCTL_OUT(req, pagesizes, len);
 	}
 	return (error);
 }
 SYSCTL_PROC(_hw, OID_AUTO, pagesizes, CTLTYPE_ULONG | CTLFLAG_RD,
     NULL, 0, sysctl_hw_pagesizes, "LU", "Supported page sizes");
 
 #ifdef SCTL_MASK32
 int adaptive_machine_arch = 1;
 SYSCTL_INT(_debug, OID_AUTO, adaptive_machine_arch, CTLFLAG_RW,
     &adaptive_machine_arch, 1,
     "Adapt reported machine architecture to the ABI of the binary");
 #endif
 
 static int
 sysctl_hw_machine_arch(SYSCTL_HANDLER_ARGS)
 {
 	int error;
 	static const char machine_arch[] = MACHINE_ARCH;
 #ifdef SCTL_MASK32
 	static const char machine_arch32[] = MACHINE_ARCH32;
 
 	if ((req->flags & SCTL_MASK32) != 0 && adaptive_machine_arch)
 		error = SYSCTL_OUT(req, machine_arch32, sizeof(machine_arch32));
 	else
 #endif
 		error = SYSCTL_OUT(req, machine_arch, sizeof(machine_arch));
 	return (error);
 
 }
 SYSCTL_PROC(_hw, HW_MACHINE_ARCH, machine_arch, CTLTYPE_STRING | CTLFLAG_RD |
     CTLFLAG_MPSAFE, NULL, 0, sysctl_hw_machine_arch, "A",
     "System architecture");
 
 SYSCTL_STRING(_kern, OID_AUTO, supported_archs, CTLFLAG_RD | CTLFLAG_MPSAFE,
 #ifdef COMPAT_FREEBSD32
     MACHINE_ARCH " " MACHINE_ARCH32, 0, "Supported architectures for binaries");
 #else
     MACHINE_ARCH, 0, "Supported architectures for binaries");
 #endif
 
 static int
 sysctl_hostname(SYSCTL_HANDLER_ARGS)
 {
 	struct prison *pr, *cpr;
 	size_t pr_offset;
 	char tmpname[MAXHOSTNAMELEN];
 	int descend, error, len;
 
 	/*
 	 * This function can set: hostname domainname hostuuid.
 	 * Keep that in mind when comments say "hostname".
 	 */
 	pr_offset = (size_t)arg1;
 	len = arg2;
 	KASSERT(len <= sizeof(tmpname),
 	    ("length %d too long for %s", len, __func__));
 
 	pr = req->td->td_ucred->cr_prison;
 	if (!(pr->pr_allow & PR_ALLOW_SET_HOSTNAME) && req->newptr)
 		return (EPERM);
 	/*
 	 * Make a local copy of hostname to get/set so we don't have to hold
 	 * the jail mutex during the sysctl copyin/copyout activities.
 	 */
 	mtx_lock(&pr->pr_mtx);
 	bcopy((char *)pr + pr_offset, tmpname, len);
 	mtx_unlock(&pr->pr_mtx);
 
 	error = sysctl_handle_string(oidp, tmpname, len, req);
 
 	if (req->newptr != NULL && error == 0) {
 		/*
 		 * Copy the locally set hostname to all jails that share
 		 * this host info.
 		 */
 		sx_slock(&allprison_lock);
 		while (!(pr->pr_flags & PR_HOST))
 			pr = pr->pr_parent;
 		mtx_lock(&pr->pr_mtx);
 		bcopy(tmpname, (char *)pr + pr_offset, len);
 		FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend)
 			if (cpr->pr_flags & PR_HOST)
 				descend = 0;
 			else
 				bcopy(tmpname, (char *)cpr + pr_offset, len);
 		mtx_unlock(&pr->pr_mtx);
 		sx_sunlock(&allprison_lock);
 	}
 	return (error);
 }
 
 SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname,
     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_CAPRD | CTLFLAG_MPSAFE,
     (void *)(offsetof(struct prison, pr_hostname)), MAXHOSTNAMELEN,
     sysctl_hostname, "A", "Hostname");
 SYSCTL_PROC(_kern, KERN_NISDOMAINNAME, domainname,
     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_CAPRD | CTLFLAG_MPSAFE,
     (void *)(offsetof(struct prison, pr_domainname)), MAXHOSTNAMELEN,
     sysctl_hostname, "A", "Name of the current YP/NIS domain");
 SYSCTL_PROC(_kern, KERN_HOSTUUID, hostuuid,
     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_CAPRD | CTLFLAG_MPSAFE,
     (void *)(offsetof(struct prison, pr_hostuuid)), HOSTUUIDLEN,
     sysctl_hostname, "A", "Host UUID");
 
 static int	regression_securelevel_nonmonotonic = 0;
 
 #ifdef REGRESSION
 SYSCTL_INT(_regression, OID_AUTO, securelevel_nonmonotonic, CTLFLAG_RW,
     &regression_securelevel_nonmonotonic, 0, "securelevel may be lowered");
 #endif
 
 static int
 sysctl_kern_securelvl(SYSCTL_HANDLER_ARGS)
 {
 	struct prison *pr, *cpr;
 	int descend, error, level;
 
 	pr = req->td->td_ucred->cr_prison;
 
 	/*
 	 * Reading the securelevel is easy, since the current jail's level
 	 * is known to be at least as secure as any higher levels.  Perform
 	 * a lockless read since the securelevel is an integer.
 	 */
 	level = pr->pr_securelevel;
 	error = sysctl_handle_int(oidp, &level, 0, req);
 	if (error || !req->newptr)
 		return (error);
 	/* Permit update only if the new securelevel exceeds the old. */
 	sx_slock(&allprison_lock);
 	mtx_lock(&pr->pr_mtx);
 	if (!regression_securelevel_nonmonotonic &&
 	    level < pr->pr_securelevel) {
 		mtx_unlock(&pr->pr_mtx);
 		sx_sunlock(&allprison_lock);
 		return (EPERM);
 	}
 	pr->pr_securelevel = level;
 	/*
 	 * Set all child jails to be at least this level, but do not lower
 	 * them (even if regression_securelevel_nonmonotonic).
 	 */
 	FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend) {
 		if (cpr->pr_securelevel < level)
 			cpr->pr_securelevel = level;
 	}
 	mtx_unlock(&pr->pr_mtx);
 	sx_sunlock(&allprison_lock);
 	return (error);
 }
 
 SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel,
     CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, sysctl_kern_securelvl,
     "I", "Current secure level");
 
 #ifdef INCLUDE_CONFIG_FILE
 /* Actual kernel configuration options. */
 extern char kernconfstring[];
 
 SYSCTL_STRING(_kern, OID_AUTO, conftxt, CTLFLAG_RD | CTLFLAG_MPSAFE,
     kernconfstring, 0, "Kernel configuration file");
 #endif
 
 static int
 sysctl_hostid(SYSCTL_HANDLER_ARGS)
 {
 	struct prison *pr, *cpr;
 	u_long tmpid;
 	int descend, error;
 
 	/*
 	 * Like sysctl_hostname, except it operates on a u_long
 	 * instead of a string, and is used only for hostid.
 	 */
 	pr = req->td->td_ucred->cr_prison;
 	if (!(pr->pr_allow & PR_ALLOW_SET_HOSTNAME) && req->newptr)
 		return (EPERM);
 	tmpid = pr->pr_hostid;
 	error = sysctl_handle_long(oidp, &tmpid, 0, req);
 
 	if (req->newptr != NULL && error == 0) {
 		sx_slock(&allprison_lock);
 		while (!(pr->pr_flags & PR_HOST))
 			pr = pr->pr_parent;
 		mtx_lock(&pr->pr_mtx);
 		pr->pr_hostid = tmpid;
 		FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend)
 			if (cpr->pr_flags & PR_HOST)
 				descend = 0;
 			else
 				cpr->pr_hostid = tmpid;
 		mtx_unlock(&pr->pr_mtx);
 		sx_sunlock(&allprison_lock);
 	}
 	return (error);
 }
 
 SYSCTL_PROC(_kern, KERN_HOSTID, hostid,
     CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE | CTLFLAG_CAPRD,
     NULL, 0, sysctl_hostid, "LU", "Host ID");
 
 /*
  * The osrelease string is copied from the global (osrelease in vers.c) into
  * prison0 by a sysinit and is inherited by child jails if not changed at jail
  * creation, so we always return the copy from the current prison data.
  */
 static int
 sysctl_osrelease(SYSCTL_HANDLER_ARGS)
 {
 	struct prison *pr;
 
 	pr = req->td->td_ucred->cr_prison;
 	return (SYSCTL_OUT(req, pr->pr_osrelease, strlen(pr->pr_osrelease) + 1));
 
 }
 
 SYSCTL_PROC(_kern, KERN_OSRELEASE, osrelease,
     CTLTYPE_STRING | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE,
     NULL, 0, sysctl_osrelease, "A", "Operating system release");
 
 /*
  * The osreldate number is copied from the global (osreldate in vers.c) into
  * prison0 by a sysinit and is inherited by child jails if not changed at jail
  * creation, so we always return the value from the current prison data.
  */
 static int
 sysctl_osreldate(SYSCTL_HANDLER_ARGS)
 {
 	struct prison *pr;
 
 	pr = req->td->td_ucred->cr_prison;
 	return (SYSCTL_OUT(req, &pr->pr_osreldate, sizeof(pr->pr_osreldate)));
 
 }
 
 /*
  * NOTICE: The *userland* release date is available in
  * /usr/include/osreldate.h
  */
 SYSCTL_PROC(_kern, KERN_OSRELDATE, osreldate,
     CTLTYPE_INT | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE,
     NULL, 0, sysctl_osreldate, "I", "Kernel release date");
 
 /*
  * The build-id is copied from the ELF section .note.gnu.build-id.  The linker 
  * script defines two variables to expose the beginning and end.  LLVM 
  * currently uses a SHA-1 hash, but other formats can be supported by checking 
  * the length of the section.
  */
 
 extern char __build_id_start[];
 extern char __build_id_end[];
 
 #define	BUILD_ID_HEADER_LEN	0x10
 #define	BUILD_ID_HASH_MAXLEN	0x14
 
 static int
 sysctl_build_id(SYSCTL_HANDLER_ARGS)
 {
 	uintptr_t sectionlen = (uintptr_t)(__build_id_end - __build_id_start);
 	int hashlen;
 	char buf[2*BUILD_ID_HASH_MAXLEN+1];
 
 	/*
 	 * The ELF note section has a four byte length for the vendor name,
 	 * four byte length for the value, and a four byte vendor specific 
 	 * type.  The name for the build id is "GNU\0".  We skip the first 16 
 	 * bytes to read the build hash.  We will return the remaining bytes up 
 	 * to 20 (SHA-1) hash size.  If the hash happens to be a custom number 
 	 * of bytes we will pad the value with zeros, as the section should be 
 	 * four byte aligned.
 	 */
 	if (sectionlen <= BUILD_ID_HEADER_LEN ||
 	    sectionlen > (BUILD_ID_HEADER_LEN + BUILD_ID_HASH_MAXLEN)) {
 	    return (ENOENT);
 	}
    
 
 	hashlen = sectionlen - BUILD_ID_HEADER_LEN;
 	for (int i = 0; i < hashlen; i++) {
 	    uint8_t c = __build_id_start[i+BUILD_ID_HEADER_LEN];
 	    snprintf(&buf[2*i], 3, "%02x", c);
 	}
 
 	return (SYSCTL_OUT(req, buf, strlen(buf) + 1));
 }
 
 SYSCTL_PROC(_kern, OID_AUTO, build_id,
     CTLTYPE_STRING | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE,
     NULL, 0, sysctl_build_id, "A", "Operating system build-id");
 
 SYSCTL_NODE(_kern, OID_AUTO, features, CTLFLAG_RD, 0, "Kernel Features");
 
 #ifdef COMPAT_FREEBSD4
 FEATURE(compat_freebsd4, "Compatible with FreeBSD 4");
 #endif
 
 #ifdef COMPAT_FREEBSD5
 FEATURE(compat_freebsd5, "Compatible with FreeBSD 5");
 #endif
 
 #ifdef COMPAT_FREEBSD6
 FEATURE(compat_freebsd6, "Compatible with FreeBSD 6");
 #endif
 
 #ifdef COMPAT_FREEBSD7
 FEATURE(compat_freebsd7, "Compatible with FreeBSD 7");
 #endif
 
 /*
  * This is really cheating.  These actually live in the libc, something
  * which I'm not quite sure is a good idea anyway, but in order for
  * getnext and friends to actually work, we define dummies here.
  *
  * XXXRW: These probably should be CTLFLAG_CAPRD.
  */
 SYSCTL_STRING(_user, USER_CS_PATH, cs_path, CTLFLAG_RD,
     "", 0, "PATH that finds all the standard utilities");
 SYSCTL_INT(_user, USER_BC_BASE_MAX, bc_base_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Max ibase/obase values in bc(1)");
 SYSCTL_INT(_user, USER_BC_DIM_MAX, bc_dim_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Max array size in bc(1)");
 SYSCTL_INT(_user, USER_BC_SCALE_MAX, bc_scale_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Max scale value in bc(1)");
 SYSCTL_INT(_user, USER_BC_STRING_MAX, bc_string_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Max string length in bc(1)");
 SYSCTL_INT(_user, USER_COLL_WEIGHTS_MAX, coll_weights_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Maximum number of weights assigned to an LC_COLLATE locale entry");
 SYSCTL_INT(_user, USER_EXPR_NEST_MAX, expr_nest_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "");
 SYSCTL_INT(_user, USER_LINE_MAX, line_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Max length (bytes) of a text-processing utility's input line");
 SYSCTL_INT(_user, USER_RE_DUP_MAX, re_dup_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Maximum number of repeats of a regexp permitted");
 SYSCTL_INT(_user, USER_POSIX2_VERSION, posix2_version, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0,
     "The version of POSIX 1003.2 with which the system attempts to comply");
 SYSCTL_INT(_user, USER_POSIX2_C_BIND, posix2_c_bind, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Whether C development supports the C bindings option");
 SYSCTL_INT(_user, USER_POSIX2_C_DEV, posix2_c_dev, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Whether system supports the C development utilities option");
 SYSCTL_INT(_user, USER_POSIX2_CHAR_TERM, posix2_char_term, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "");
 SYSCTL_INT(_user, USER_POSIX2_FORT_DEV, posix2_fort_dev, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Whether system supports FORTRAN development utilities");
 SYSCTL_INT(_user, USER_POSIX2_FORT_RUN, posix2_fort_run, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Whether system supports FORTRAN runtime utilities");
 SYSCTL_INT(_user, USER_POSIX2_LOCALEDEF, posix2_localedef, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Whether system supports creation of locales");
 SYSCTL_INT(_user, USER_POSIX2_SW_DEV, posix2_sw_dev, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Whether system supports software development utilities");
 SYSCTL_INT(_user, USER_POSIX2_UPE, posix2_upe, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Whether system supports the user portability utilities");
 SYSCTL_INT(_user, USER_STREAM_MAX, stream_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Min Maximum number of streams a process may have open at one time");
 SYSCTL_INT(_user, USER_TZNAME_MAX, tzname_max, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, 0, "Min Maximum number of types supported for timezone names");
 
 #include <sys/vnode.h>
 SYSCTL_INT(_debug_sizeof, OID_AUTO, vnode, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, sizeof(struct vnode), "sizeof(struct vnode)");
 
 SYSCTL_INT(_debug_sizeof, OID_AUTO, proc, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, sizeof(struct proc), "sizeof(struct proc)");
 
 static int
 sysctl_kern_pid_max(SYSCTL_HANDLER_ARGS)
 {
 	int error, pm;
 
 	pm = pid_max;
 	error = sysctl_handle_int(oidp, &pm, 0, req);
 	if (error || !req->newptr)
 		return (error);
 	sx_xlock(&proctree_lock);
 	sx_xlock(&allproc_lock);
 
 	/*
 	 * Only permit the values less then PID_MAX.
 	 * As a safety measure, do not allow to limit the pid_max too much.
 	 */
 	if (pm < 300 || pm > PID_MAX)
 		error = EINVAL;
 	else
 		pid_max = pm;
 	sx_xunlock(&allproc_lock);
 	sx_xunlock(&proctree_lock);
 	return (error);
 }
 SYSCTL_PROC(_kern, OID_AUTO, pid_max, CTLTYPE_INT |
     CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_MPSAFE,
     0, 0, sysctl_kern_pid_max, "I", "Maximum allowed pid");
 
 #include <sys/bio.h>
 #include <sys/buf.h>
 SYSCTL_INT(_debug_sizeof, OID_AUTO, bio, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, sizeof(struct bio), "sizeof(struct bio)");
 SYSCTL_INT(_debug_sizeof, OID_AUTO, buf, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, sizeof(struct buf), "sizeof(struct buf)");
 
 #include <sys/user.h>
 SYSCTL_INT(_debug_sizeof, OID_AUTO, kinfo_proc, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, sizeof(struct kinfo_proc), "sizeof(struct kinfo_proc)");
 
 /* Used by kernel debuggers. */
 const int pcb_size = sizeof(struct pcb);
 SYSCTL_INT(_debug_sizeof, OID_AUTO, pcb, CTLFLAG_RD,
     SYSCTL_NULL_INT_PTR, sizeof(struct pcb), "sizeof(struct pcb)");
 
 /* XXX compatibility, remove for 6.0 */
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
 SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW,
     &__elfN(fallback_brand), sizeof(__elfN(fallback_brand)),
     "compatibility for kern.fallback_elf_brand");
diff --git a/sys/libkern/arc4random.c b/sys/libkern/arc4random.c
index ad4c6b057e4a..cdc303e9d309 100644
--- a/sys/libkern/arc4random.c
+++ b/sys/libkern/arc4random.c
@@ -1,203 +1,183 @@
 /*-
  * Copyright (c) 2017 The FreeBSD Foundation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/libkern.h>
 #include <sys/linker.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/random.h>
 #include <sys/smp.h>
 #include <sys/time.h>
 
 #include <crypto/chacha20/chacha.h>
 
 #define	CHACHA20_RESEED_BYTES	65536
 #define	CHACHA20_RESEED_SECONDS	300
 #define	CHACHA20_KEYBYTES	32
 #define	CHACHA20_BUFFER_SIZE	64
 
 CTASSERT(CHACHA20_KEYBYTES*8 >= CHACHA_MINKEYLEN);
 
 int arc4rand_iniseed_state = ARC4_ENTR_NONE;
 
 MALLOC_DEFINE(M_CHACHA20RANDOM, "chacha20random", "chacha20random structures");
 
 struct chacha20_s {
 	struct mtx mtx;
 	int numbytes;
-	int first_time_done;
 	time_t t_reseed;
 	u_int8_t m_buffer[CHACHA20_BUFFER_SIZE];
 	struct chacha_ctx ctx;
 } __aligned(CACHE_LINE_SIZE);
 
 static struct chacha20_s *chacha20inst = NULL;
 
 #define CHACHA20_FOREACH(_chacha20) \
 	for (_chacha20 = &chacha20inst[0]; \
 	     _chacha20 <= &chacha20inst[mp_maxid]; \
 	     _chacha20++)
 
 /*
  * Mix up the current context.
  */
 static void
-chacha20_randomstir(struct chacha20_s* chacha20)
+chacha20_randomstir(struct chacha20_s *chacha20)
 {
 	struct timeval tv_now;
-	size_t n, size;
-	u_int8_t key[CHACHA20_KEYBYTES], *data;
-	caddr_t keyfile;
+	u_int8_t key[CHACHA20_KEYBYTES];
 
 	/*
-	 * This is making the best of what may be an insecure
-	 * Situation. If the loader(8) did not have an entropy
-	 * stash from the previous shutdown to load, then we will
-	 * be improperly seeded. The answer is to make sure there
-	 * is an entropy stash at shutdown time.
+	 * If the loader(8) did not have an entropy stash from the previous
+	 * shutdown to load, then we will block.  The answer is to make sure
+	 * there is an entropy stash at shutdown time.
 	 */
-	(void)read_random(key, CHACHA20_KEYBYTES);
-	if (!chacha20->first_time_done) {
-		keyfile = preload_search_by_type(RANDOM_CACHED_BOOT_ENTROPY_MODULE);
-		if (keyfile != NULL) {
-			data = preload_fetch_addr(keyfile);
-			size = MIN(preload_fetch_size(keyfile), CHACHA20_KEYBYTES);
-			for (n = 0; n < size; n++)
-				key[n] ^= data[n];
-			explicit_bzero(data, size);
-			if (bootverbose)
-				printf("arc4random: read %zu bytes from preloaded cache\n", size);
-		} else
-			printf("arc4random: no preloaded entropy cache\n");
-		chacha20->first_time_done = 1;
-	}
+	read_random(key, CHACHA20_KEYBYTES);
 	getmicrouptime(&tv_now);
 	mtx_lock(&chacha20->mtx);
 	chacha_keysetup(&chacha20->ctx, key, CHACHA20_KEYBYTES*8);
 	chacha_ivsetup(&chacha20->ctx, (u_char *)&tv_now.tv_sec, (u_char *)&tv_now.tv_usec);
 	/* Reset for next reseed cycle. */
 	chacha20->t_reseed = tv_now.tv_sec + CHACHA20_RESEED_SECONDS;
 	chacha20->numbytes = 0;
 	mtx_unlock(&chacha20->mtx);
 }
 
 /*
  * Initialize the contexts.
  */
 static void
 chacha20_init(void)
 {
 	struct chacha20_s *chacha20;
 
 	chacha20inst = malloc((mp_maxid + 1) * sizeof(struct chacha20_s),
 			M_CHACHA20RANDOM, M_NOWAIT | M_ZERO);
 	KASSERT(chacha20inst != NULL, ("chacha20_init: memory allocation error"));
 
 	CHACHA20_FOREACH(chacha20) {
 		mtx_init(&chacha20->mtx, "chacha20_mtx", NULL, MTX_DEF);
 		chacha20->t_reseed = -1;
 		chacha20->numbytes = 0;
-		chacha20->first_time_done = 0;
 		explicit_bzero(chacha20->m_buffer, CHACHA20_BUFFER_SIZE);
 		explicit_bzero(&chacha20->ctx, sizeof(chacha20->ctx));
 	}
 }
 SYSINIT(chacha20, SI_SUB_LOCK, SI_ORDER_ANY, chacha20_init, NULL);
 
 
 static void
 chacha20_uninit(void)
 {
 	struct chacha20_s *chacha20;
 
 	CHACHA20_FOREACH(chacha20)
 		mtx_destroy(&chacha20->mtx);
 	free(chacha20inst, M_CHACHA20RANDOM);
 }
 SYSUNINIT(chacha20, SI_SUB_LOCK, SI_ORDER_ANY, chacha20_uninit, NULL);
 
 
 /*
  * MPSAFE
  */
 void
 arc4rand(void *ptr, u_int len, int reseed)
 {
 	struct chacha20_s *chacha20;
 	struct timeval tv;
 	u_int length;
 	u_int8_t *p;
 
 	if (reseed || atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_HAVE, ARC4_ENTR_SEED))
 		CHACHA20_FOREACH(chacha20)
 			chacha20_randomstir(chacha20);
 
 	chacha20 = &chacha20inst[curcpu];
 	getmicrouptime(&tv);
 	/* We may get unlucky and be migrated off this CPU, but that is expected to be infrequent */
 	if ((chacha20->numbytes > CHACHA20_RESEED_BYTES) || (tv.tv_sec > chacha20->t_reseed))
 		chacha20_randomstir(chacha20);
 
 	mtx_lock(&chacha20->mtx);
 	p = ptr;
 	while (len) {
 		length = MIN(CHACHA20_BUFFER_SIZE, len);
 		chacha_encrypt_bytes(&chacha20->ctx, chacha20->m_buffer, p, length);
 		p += length;
 		len -= length;
 		chacha20->numbytes += length;
 		if (chacha20->numbytes > CHACHA20_RESEED_BYTES) {
 			mtx_unlock(&chacha20->mtx);
 			chacha20_randomstir(chacha20);
 			mtx_lock(&chacha20->mtx);
 		}
 	}
 	mtx_unlock(&chacha20->mtx);
 }
 
 uint32_t
 arc4random(void)
 {
 	uint32_t ret;
 
 	arc4rand(&ret, sizeof(ret), 0);
 	return ret;
 }
 
 void
 arc4random_buf(void *ptr, size_t len)
 {
 
 	arc4rand(ptr, len, 0);
 }
diff --git a/sys/sys/random.h b/sys/sys/random.h
index a94d3f378a28..f64728e79b8d 100644
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -1,166 +1,164 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2000-2015, 2017 Mark R. V. Murray
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #ifndef	_SYS_RANDOM_H_
 #define	_SYS_RANDOM_H_
 
 #include <sys/types.h>
 
 #ifdef _KERNEL
 
 struct uio;
 
 #if defined(DEV_RANDOM)
-u_int read_random(void *, u_int);
+void read_random(void *, u_int);
 int read_random_uio(struct uio *, bool);
 #else
 static __inline int
 read_random_uio(void *a __unused, u_int b __unused)
 {
 	return (0);
 }
-static __inline u_int
+static __inline void
 read_random(void *a __unused, u_int b __unused)
 {
-	return (0);
 }
 #endif
 
 /*
  * Note: if you add or remove members of random_entropy_source, remember to
  * also update the strings in the static array random_source_descr[] in
  * random_harvestq.c.
  *
  * NOTE: complain loudly to markm@ or on the lists if this enum gets more than 32
  * distinct values (0-31)! ENTROPYSOURCE may be == 32, but not > 32.
  */
 enum random_entropy_source {
 	RANDOM_START = 0,
 	RANDOM_CACHED = 0,
 	/* Environmental sources */
 	RANDOM_ATTACH,
 	RANDOM_KEYBOARD,
 	RANDOM_MOUSE,
 	RANDOM_NET_TUN,
 	RANDOM_NET_ETHER,
 	RANDOM_NET_NG,
 	RANDOM_INTERRUPT,
 	RANDOM_SWI,
 	RANDOM_FS_ATIME,
 	RANDOM_UMA,	/* Special!! UMA/SLAB Allocator */
 	RANDOM_ENVIRONMENTAL_END = RANDOM_UMA,
 	/* Fast hardware random-number sources from here on. */
 	RANDOM_PURE_START,
 	RANDOM_PURE_OCTEON = RANDOM_PURE_START,
 	RANDOM_PURE_SAFE,
 	RANDOM_PURE_GLXSB,
 	RANDOM_PURE_UBSEC,
 	RANDOM_PURE_HIFN,
 	RANDOM_PURE_RDRAND,
 	RANDOM_PURE_NEHEMIAH,
 	RANDOM_PURE_RNDTEST,
 	RANDOM_PURE_VIRTIO,
 	RANDOM_PURE_BROADCOM,
 	RANDOM_PURE_CCP,
 	RANDOM_PURE_DARN,
 	RANDOM_PURE_TPM,
 	ENTROPYSOURCE
 };
 
 #define RANDOM_HARVEST_EVERYTHING_MASK ((1 << (RANDOM_ENVIRONMENTAL_END + 1)) - 1)
 #define RANDOM_HARVEST_PURE_MASK (((1 << ENTROPYSOURCE) - 1) & (-1UL << RANDOM_PURE_START))
 
 #define RANDOM_LEGACY_BOOT_ENTROPY_MODULE	"/boot/entropy"
 #define RANDOM_CACHED_BOOT_ENTROPY_MODULE	"boot_entropy_cache"
-#define	RANDOM_CACHED_SKIP_START	256
 
 #if defined(DEV_RANDOM)
 extern u_int hc_source_mask;
 void random_harvest_queue_(const void *, u_int, enum random_entropy_source);
 void random_harvest_fast_(const void *, u_int);
 void random_harvest_direct_(const void *, u_int, enum random_entropy_source);
 
 static __inline void
 random_harvest_queue(const void *entropy, u_int size, enum random_entropy_source origin)
 {
 
 	if (hc_source_mask & (1 << origin))
 		random_harvest_queue_(entropy, size, origin);
 }
 
 static __inline void
 random_harvest_fast(const void *entropy, u_int size, enum random_entropy_source origin)
 {
 
 	if (hc_source_mask & (1 << origin))
 		random_harvest_fast_(entropy, size);
 }
 
 static __inline void
 random_harvest_direct(const void *entropy, u_int size, enum random_entropy_source origin)
 {
 
 	if (hc_source_mask & (1 << origin))
 		random_harvest_direct_(entropy, size, origin);
 }
 
 void random_harvest_register_source(enum random_entropy_source);
 void random_harvest_deregister_source(enum random_entropy_source);
 #else
 #define random_harvest_queue(a, b, c) do {} while (0)
 #define random_harvest_fast(a, b, c) do {} while (0)
 #define random_harvest_direct(a, b, c) do {} while (0)
 #define random_harvest_register_source(a) do {} while (0)
 #define random_harvest_deregister_source(a) do {} while (0)
 #endif
 
 #if defined(RANDOM_ENABLE_UMA)
 #define random_harvest_fast_uma(a, b, c)	random_harvest_fast(a, b, c)
 #else /* !defined(RANDOM_ENABLE_UMA) */
 #define random_harvest_fast_uma(a, b, c)	do {} while (0)
 #endif /* defined(RANDOM_ENABLE_UMA) */
 
 #if defined(RANDOM_ENABLE_ETHER)
 #define random_harvest_queue_ether(a, b)	random_harvest_queue(a, b, RANDOM_NET_ETHER)
 #else /* !defined(RANDOM_ENABLE_ETHER) */
 #define random_harvest_queue_ether(a, b)	do {} while (0)
 #endif /* defined(RANDOM_ENABLE_ETHER) */
 
 
 #endif /* _KERNEL */
 
 #define GRND_NONBLOCK	0x1
 #define GRND_RANDOM	0x2
 
 __BEGIN_DECLS
 ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
 __END_DECLS
 
 #endif /* _SYS_RANDOM_H_ */