From 78cb1213ad35895b6d0d1a1ff49224f0c123e86c Mon Sep 17 00:00:00 2001
From: Stephan Mueller <smueller@chronox.de>
Date: Sun, 18 Dec 2022 21:22:36 +0100
Subject: [PATCH 19/25] LRNG - add interface for gathering of raw entropy

The test interface allows a privileged process to capture the raw
unconditioned noise that is collected by the LRNG for statistical
analysis. Such testing allows the analysis how much entropy
the interrupt noise source provides on a given platform.
Extracted noise data is not used to seed the LRNG. This
is a test interface and not appropriate for production systems.
Yet, the interface is considered to be sufficiently secured for
production systems.

The raw entropy collection is provided for the internal entropy sources
under full control of the LRNG: the IRQ ES and the scheduler-based ES.
The test interfaces are only enabled for the given ES if the ES is
enabled itself.

Access to the data is given through the lrng_raw debugfs file. The
data buffer should be multiples of sizeof(u32) to fill the entire
buffer. Using the option lrng_testing.boot_test=1 the raw noise of
the first 1000 entropy events since boot can be sampled.

This test interface allows generating the data required for
analysis whether the LRNG is in compliance with SP800-90B
sections 3.1.3 and 3.1.4.

In addition, the test interface allows gathering of the concatenated raw
entropy data to verify that the concatenation works appropriately.
This includes sampling of the following raw IRQ data:

* high-resolution time stamp obtained for an IRQ event

* Jiffies

* IRQ number

* return instruction pointer

* interrupt register state

* array logic batching the high-resolution time stamp

* a performance monitor of the IRQ ES

The sampling of the following scheduler-based ES data is possible:

* high-resolution time stamp obtained for a context switch event

* the PID of the process scheduled to

* the process' start time value

* the process' context switch numbers value

* a performance monitor of the scheduler-based ES

Also, a testing interface to support ACVT of the hash implementation
is provided. The reason why only hash testing is supported (as
opposed to also provide testing for the DRNG) is the fact that the
LRNG software hash implementation contains glue code that may
warrant testing in addition to the testing of the software ciphers
via the kernel crypto API. Also, for testing the CTR-DRBG, the
underlying AES implementation would need to be tested. However,
such AES test interface cannot be provided by the LRNG as it has no
means to access the AES operation.

If a test interface is not compiled, its code is a noop which has no
impact on the performance.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 drivers/char/lrng/Kconfig        | 534 +++++++++---------
 drivers/char/lrng/Makefile       |   1 +
 drivers/char/lrng/lrng_testing.c | 901 +++++++++++++++++++++++++++++++
 3 files changed, 1169 insertions(+), 267 deletions(-)
 create mode 100644 drivers/char/lrng/lrng_testing.c

--- a/drivers/char/lrng/Kconfig
+++ b/drivers/char/lrng/Kconfig
@@ -718,273 +718,273 @@ choice
 		select LRNG_DRNG_KCAPI
 endchoice
 
-# menuconfig LRNG_TESTING_MENU
-# 	bool "LRNG testing interfaces"
-# 	depends on DEBUG_FS
-# 	help
-# 	  Enable one or more of the following test interfaces.
-#
-# 	  If unsure, say N.
-#
-# if LRNG_TESTING_MENU
-#
-# config LRNG_TESTING
-# 	bool
-#
-# config LRNG_TESTING_RECORDING
-# 	bool
-#
-# comment "Interrupt Entropy Source Test Interfaces"
-#
-# config LRNG_RAW_HIRES_ENTROPY
-# 	bool "Interface to obtain raw unprocessed IRQ noise source data"
-# 	default y
-# 	depends on LRNG_IRQ
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned high resolution time stamp noise that
-# 	  is collected by the LRNG for statistical analysis. Extracted
-# 	  noise data is not used to seed the LRNG.
-#
-# 	  The raw noise data can be obtained using the lrng_raw_hires
-# 	  debugfs file. Using the option lrng_testing.boot_raw_hires_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_RAW_JIFFIES_ENTROPY
-# 	bool "Entropy test interface to Jiffies of IRQ noise source"
-# 	depends on LRNG_IRQ
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned Jiffies that is collected by
-# 	  the LRNG for statistical analysis. This data is used for
-# 	  seeding the LRNG if a high-resolution time stamp is not
-# 	  available. If a high-resolution time stamp is detected,
-# 	  the Jiffies value is not collected by the LRNG and no
-# 	  data is provided via the test interface. Extracted noise
-# 	  data is not used to seed the random number generator.
-#
-# 	  The raw noise data can be obtained using the lrng_raw_jiffies
-# 	  debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_RAW_IRQ_ENTROPY
-# 	bool "Entropy test interface to IRQ number noise source"
-# 	depends on LRNG_IRQ
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned interrupt number that is collected by
-# 	  the LRNG for statistical analysis. Extracted noise data is
-# 	  not used to seed the random number generator.
-#
-# 	  The raw noise data can be obtained using the lrng_raw_irq
-# 	  debugfs file. Using the option lrng_testing.boot_raw_irq_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_RAW_RETIP_ENTROPY
-# 	bool "Entropy test interface to RETIP value of IRQ noise source"
-# 	depends on LRNG_IRQ
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned return instruction pointer value
-# 	  that is collected by the LRNG for statistical analysis.
-# 	  Extracted noise data is not used to seed the random number
-# 	  generator.
-#
-# 	  The raw noise data can be obtained using the lrng_raw_retip
-# 	  debugfs file. Using the option lrng_testing.boot_raw_retip_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_RAW_REGS_ENTROPY
-# 	bool "Entropy test interface to IRQ register value noise source"
-# 	depends on LRNG_IRQ
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned interrupt register value that is
-# 	  collected by the LRNG for statistical analysis. Extracted noise
-# 	  data is not used to seed the random number generator.
-#
-# 	  The raw noise data can be obtained using the lrng_raw_regs
-# 	  debugfs file. Using the option lrng_testing.boot_raw_regs_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_RAW_ARRAY
-# 	bool "Test interface to LRNG raw entropy IRQ storage array"
-# 	depends on LRNG_IRQ
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw noise data that is collected by the LRNG
-# 	  in the per-CPU array for statistical analysis. The purpose
-# 	  of this interface is to verify that the array handling code
-# 	  truly only concatenates data and provides the same entropy
-# 	  rate as the raw unconditioned noise source when assessing
-# 	  the collected data byte-wise.
-#
-# 	  The data can be obtained using the lrng_raw_array debugfs
-# 	  file. Using the option lrng_testing.boot_raw_array=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_IRQ_PERF
-# 	bool "LRNG interrupt entropy source performance monitor"
-# 	depends on LRNG_IRQ
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  With this option, the performance monitor of the LRNG
-# 	  interrupt handling code is enabled. The file provides
-# 	  the execution time of the interrupt handler in
-# 	  cycles.
-#
-# 	  The interrupt performance data can be obtained using
-# 	  the lrng_irq_perf debugfs file. Using the option
-# 	  lrng_testing.boot_irq_perf=1 the performance data of
-# 	  the first 1000 entropy events since boot can be sampled.
-#
-# comment "Scheduler Entropy Source Test Interfaces"
-#
-# config LRNG_RAW_SCHED_HIRES_ENTROPY
-# 	bool "Interface to obtain raw unprocessed scheduler noise source data"
-# 	depends on LRNG_SCHED
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned high resolution time stamp noise that
-# 	  is collected by the LRNG for the Scheduler-based noise source
-# 	  for statistical analysis. Extracted  noise data is not used to
-# 	  seed the LRNG.
-#
-# 	  The raw noise data can be obtained using the lrng_raw_sched_hires
-# 	  debugfs file. Using the option
-# 	  lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the
-# 	  first 1000 entropy events since boot can be sampled.
-#
-# config LRNG_RAW_SCHED_PID_ENTROPY
-# 	bool "Entropy test interface to PID value"
-# 	depends on LRNG_SCHED
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned PID value that is collected by the
-# 	  LRNG for statistical analysis. Extracted noise
-# 	  data is not used to seed the random number generator.
-#
-# 	  The raw noise data can be obtained using the
-# 	  lrng_raw_sched_pid debugfs file. Using the option
-# 	  lrng_testing.boot_raw_sched_pid_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_RAW_SCHED_START_TIME_ENTROPY
-# 	bool "Entropy test interface to task start time value"
-# 	depends on LRNG_SCHED
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned task start time value that is collected
-# 	  by the LRNG for statistical analysis. Extracted noise
-# 	  data is not used to seed the random number generator.
-#
-# 	  The raw noise data can be obtained using the
-# 	  lrng_raw_sched_starttime debugfs file. Using the option
-# 	  lrng_testing.boot_raw_sched_starttime_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-#
-# config LRNG_RAW_SCHED_NVCSW_ENTROPY
-# 	bool "Entropy test interface to task context switch numbers"
-# 	depends on LRNG_SCHED
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  The test interface allows a privileged process to capture
-# 	  the raw unconditioned task numbers of context switches that
-# 	  are collected by the LRNG for statistical analysis. Extracted
-# 	  noise data is not used to seed the random number generator.
-#
-# 	  The raw noise data can be obtained using the
-# 	  lrng_raw_sched_nvcsw debugfs file. Using the option
-# 	  lrng_testing.boot_raw_sched_nvcsw_test=1
-# 	  the raw noise of the first 1000 entropy events since boot
-# 	  can be sampled.
-#
-# config LRNG_SCHED_PERF
-# 	bool "LRNG scheduler entropy source performance monitor"
-# 	depends on LRNG_SCHED
-# 	select LRNG_TESTING
-# 	select LRNG_TESTING_RECORDING
-# 	help
-# 	  With this option, the performance monitor of the LRNG
-# 	  scheduler event handling code is enabled. The file provides
-# 	  the execution time of the interrupt handler in cycles.
-#
-# 	  The scheduler performance data can be obtained using
-# 	  the lrng_sched_perf debugfs file. Using the option
-# 	  lrng_testing.boot_sched_perf=1 the performance data of
-# 	  the first 1000 entropy events since boot can be sampled.
-#
-# comment "Auxiliary Test Interfaces"
-#
-# config LRNG_ACVT_HASH
-# 	bool "Enable LRNG ACVT Hash interface"
-# 	select LRNG_TESTING
-# 	help
-# 	  With this option, the LRNG built-in hash function used for
-# 	  auxiliary pool management and prior to switching the
-# 	  cryptographic backends is made available for ACVT. The
-# 	  interface allows writing of the data to be hashed
-# 	  into the interface. The read operation triggers the hash
-# 	  operation to generate message digest.
-#
-# 	  The ACVT interface is available with the lrng_acvt_hash
-# 	  debugfs file.
-#
-# config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG
-# 	bool "Enable runtime configuration of max reseed threshold"
-# 	help
-# 	  When enabling this option, the LRNG provides an interface
-# 	  allowing the setting of the maximum number of DRNG generate
-# 	  operations without a reseed that has full entropy. The
-# 	  interface is lrng_drng.max_wo_reseed.
-#
-#config LRNG_RUNTIME_FORCE_SEEDING_DISABLE
-#	bool "Enable runtime configuration of force seeding"
-#	help
-#	  When enabling this option, the LRNG provides an interface
-#	  allowing the disabling of the force seeding when the DRNG
-#	  is not fully seeded but entropy is available.
-#
-# config LRNG_TEST_CPU_ES_COMPRESSION
-# 	bool "Force CPU ES compression operation"
-# 	help
-# 	  When enabling this option, the CPU ES compression operation
-# 	  is forced by setting an arbitrary value > 1 for the data
-# 	  multiplier even when the CPU ES would deliver full entropy.
-# 	  This allows testing of the compression operation. It
-# 	  therefore forces to pull more data from the CPU ES
-# 	  than what may be required.
-#
-# endif #LRNG_TESTING_MENU
+menuconfig LRNG_TESTING_MENU
+	bool "LRNG testing interfaces"
+	depends on DEBUG_FS
+	help
+	  Enable one or more of the following test interfaces.
+
+	  If unsure, say N.
+
+if LRNG_TESTING_MENU
+
+config LRNG_TESTING
+	bool
+
+config LRNG_TESTING_RECORDING
+	bool
+
+comment "Interrupt Entropy Source Test Interfaces"
+
+config LRNG_RAW_HIRES_ENTROPY
+	bool "Interface to obtain raw unprocessed IRQ noise source data"
+	default y
+	depends on LRNG_IRQ
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned high resolution time stamp noise that
+	  is collected by the LRNG for statistical analysis. Extracted
+	  noise data is not used to seed the LRNG.
+
+	  The raw noise data can be obtained using the lrng_raw_hires
+	  debugfs file. Using the option lrng_testing.boot_raw_hires_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_RAW_JIFFIES_ENTROPY
+	bool "Entropy test interface to Jiffies of IRQ noise source"
+	depends on LRNG_IRQ
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned Jiffies that is collected by
+	  the LRNG for statistical analysis. This data is used for
+	  seeding the LRNG if a high-resolution time stamp is not
+	  available. If a high-resolution time stamp is detected,
+	  the Jiffies value is not collected by the LRNG and no
+	  data is provided via the test interface. Extracted noise
+	  data is not used to seed the random number generator.
+
+	  The raw noise data can be obtained using the lrng_raw_jiffies
+	  debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_RAW_IRQ_ENTROPY
+	bool "Entropy test interface to IRQ number noise source"
+	depends on LRNG_IRQ
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned interrupt number that is collected by
+	  the LRNG for statistical analysis. Extracted noise data is
+	  not used to seed the random number generator.
+
+	  The raw noise data can be obtained using the lrng_raw_irq
+	  debugfs file. Using the option lrng_testing.boot_raw_irq_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_RAW_RETIP_ENTROPY
+	bool "Entropy test interface to RETIP value of IRQ noise source"
+	depends on LRNG_IRQ
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned return instruction pointer value
+	  that is collected by the LRNG for statistical analysis.
+	  Extracted noise data is not used to seed the random number
+	  generator.
+
+	  The raw noise data can be obtained using the lrng_raw_retip
+	  debugfs file. Using the option lrng_testing.boot_raw_retip_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_RAW_REGS_ENTROPY
+	bool "Entropy test interface to IRQ register value noise source"
+	depends on LRNG_IRQ
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned interrupt register value that is
+	  collected by the LRNG for statistical analysis. Extracted noise
+	  data is not used to seed the random number generator.
+
+	  The raw noise data can be obtained using the lrng_raw_regs
+	  debugfs file. Using the option lrng_testing.boot_raw_regs_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_RAW_ARRAY
+	bool "Test interface to LRNG raw entropy IRQ storage array"
+	depends on LRNG_IRQ
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw noise data that is collected by the LRNG
+	  in the per-CPU array for statistical analysis. The purpose
+	  of this interface is to verify that the array handling code
+	  truly only concatenates data and provides the same entropy
+	  rate as the raw unconditioned noise source when assessing
+	  the collected data byte-wise.
+
+	  The data can be obtained using the lrng_raw_array debugfs
+	  file. Using the option lrng_testing.boot_raw_array=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_IRQ_PERF
+	bool "LRNG interrupt entropy source performance monitor"
+	depends on LRNG_IRQ
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  With this option, the performance monitor of the LRNG
+	  interrupt handling code is enabled. The file provides
+	  the execution time of the interrupt handler in
+	  cycles.
+
+	  The interrupt performance data can be obtained using
+	  the lrng_irq_perf debugfs file. Using the option
+	  lrng_testing.boot_irq_perf=1 the performance data of
+	  the first 1000 entropy events since boot can be sampled.
+
+comment "Scheduler Entropy Source Test Interfaces"
+
+config LRNG_RAW_SCHED_HIRES_ENTROPY
+	bool "Interface to obtain raw unprocessed scheduler noise source data"
+	depends on LRNG_SCHED
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned high resolution time stamp noise that
+	  is collected by the LRNG for the Scheduler-based noise source
+	  for statistical analysis. Extracted  noise data is not used to
+	  seed the LRNG.
+
+	  The raw noise data can be obtained using the lrng_raw_sched_hires
+	  debugfs file. Using the option
+	  lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the
+	  first 1000 entropy events since boot can be sampled.
+
+config LRNG_RAW_SCHED_PID_ENTROPY
+	bool "Entropy test interface to PID value"
+	depends on LRNG_SCHED
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned PID value that is collected by the
+	  LRNG for statistical analysis. Extracted noise
+	  data is not used to seed the random number generator.
+
+	  The raw noise data can be obtained using the
+	  lrng_raw_sched_pid debugfs file. Using the option
+	  lrng_testing.boot_raw_sched_pid_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_RAW_SCHED_START_TIME_ENTROPY
+	bool "Entropy test interface to task start time value"
+	depends on LRNG_SCHED
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned task start time value that is collected
+	  by the LRNG for statistical analysis. Extracted noise
+	  data is not used to seed the random number generator.
+
+	  The raw noise data can be obtained using the
+	  lrng_raw_sched_starttime debugfs file. Using the option
+	  lrng_testing.boot_raw_sched_starttime_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+
+config LRNG_RAW_SCHED_NVCSW_ENTROPY
+	bool "Entropy test interface to task context switch numbers"
+	depends on LRNG_SCHED
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  The test interface allows a privileged process to capture
+	  the raw unconditioned task numbers of context switches that
+	  are collected by the LRNG for statistical analysis. Extracted
+	  noise data is not used to seed the random number generator.
+
+	  The raw noise data can be obtained using the
+	  lrng_raw_sched_nvcsw debugfs file. Using the option
+	  lrng_testing.boot_raw_sched_nvcsw_test=1
+	  the raw noise of the first 1000 entropy events since boot
+	  can be sampled.
+
+config LRNG_SCHED_PERF
+	bool "LRNG scheduler entropy source performance monitor"
+	depends on LRNG_SCHED
+	select LRNG_TESTING
+	select LRNG_TESTING_RECORDING
+	help
+	  With this option, the performance monitor of the LRNG
+	  scheduler event handling code is enabled. The file provides
+	  the execution time of the interrupt handler in cycles.
+
+	  The scheduler performance data can be obtained using
+	  the lrng_sched_perf debugfs file. Using the option
+	  lrng_testing.boot_sched_perf=1 the performance data of
+	  the first 1000 entropy events since boot can be sampled.
+
+comment "Auxiliary Test Interfaces"
+
+config LRNG_ACVT_HASH
+	bool "Enable LRNG ACVT Hash interface"
+	select LRNG_TESTING
+	help
+	  With this option, the LRNG built-in hash function used for
+	  auxiliary pool management and prior to switching the
+	  cryptographic backends is made available for ACVT. The
+	  interface allows writing of the data to be hashed
+	  into the interface. The read operation triggers the hash
+	  operation to generate message digest.
+
+	  The ACVT interface is available with the lrng_acvt_hash
+	  debugfs file.
+
+config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG
+	bool "Enable runtime configuration of max reseed threshold"
+	help
+	  When enabling this option, the LRNG provides an interface
+	  allowing the setting of the maximum number of DRNG generate
+	  operations without a reseed that has full entropy. The
+	  interface is lrng_drng.max_wo_reseed.
+
+config LRNG_RUNTIME_FORCE_SEEDING_DISABLE
+	bool "Enable runtime configuration of force seeding"
+	help
+	  When enabling this option, the LRNG provides an interface
+	  allowing the disabling of the force seeding when the DRNG
+	  is not fully seeded but entropy is available.
+
+config LRNG_TEST_CPU_ES_COMPRESSION
+	bool "Force CPU ES compression operation"
+	help
+	  When enabling this option, the CPU ES compression operation
+	  is forced by setting an arbitrary value > 1 for the data
+	  multiplier even when the CPU ES would deliver full entropy.
+	  This allows testing of the compression operation. It
+	  therefore forces to pull more data from the CPU ES
+	  than what may be required.
+
+endif #LRNG_TESTING_MENU
 #
 # config LRNG_SELFTEST
 # 	bool "Enable power-on and on-demand self-tests"
--- a/drivers/char/lrng/Makefile
+++ b/drivers/char/lrng/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_LRNG_CPU)			+= lrng_es_cpu.
 obj-$(CONFIG_LRNG_JENT)			+= lrng_es_jent.o
 
 obj-$(CONFIG_LRNG_HEALTH_TESTS)		+= lrng_health.o
+obj-$(CONFIG_LRNG_TESTING)		+= lrng_testing.o
--- /dev/null
+++ b/drivers/char/lrng/lrng_testing.c
@@ -0,0 +1,901 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG testing interfaces to obtain raw entropy
+ *
+ * Copyright (C) 2022, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/lrng.h>
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <asm/errno.h>
+
+#include "lrng_definitions.h"
+#include "lrng_drng_chacha20.h"
+#include "lrng_sha.h"
+#include "lrng_testing.h"
+
+#if defined(CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY) ||		\
+    defined(CONFIG_LRNG_RAW_SCHED_PID_ENTROPY) ||		\
+    defined(CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY) ||	\
+    defined(CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY) ||		\
+    defined(CONFIG_LRNG_SCHED_PERF)
+#define LRNG_TESTING_USE_BUSYLOOP
+#endif
+
+#ifdef CONFIG_LRNG_TESTING_RECORDING
+
+#define LRNG_TESTING_RINGBUFFER_SIZE	1024
+#define LRNG_TESTING_RINGBUFFER_MASK	(LRNG_TESTING_RINGBUFFER_SIZE - 1)
+
+struct lrng_testing {
+	u32 lrng_testing_rb[LRNG_TESTING_RINGBUFFER_SIZE];
+	u32 rb_reader;
+	atomic_t rb_writer;
+	atomic_t lrng_testing_enabled;
+	spinlock_t lock;
+	wait_queue_head_t read_wait;
+};
+
+/*************************** Generic Data Handling ****************************/
+
+/*
+ * boot variable:
+ * 0 ==> No boot test, gathering of runtime data allowed
+ * 1 ==> Boot test enabled and ready for collecting data, gathering runtime
+ *	 data is disabled
+ * 2 ==> Boot test completed and disabled, gathering of runtime data is
+ *	 disabled
+ */
+
+static void lrng_testing_reset(struct lrng_testing *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->lock, flags);
+	data->rb_reader = 0;
+	atomic_set(&data->rb_writer, 0);
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static void lrng_testing_init(struct lrng_testing *data, u32 boot)
+{
+	/*
+	 * The boot time testing implies we have a running test. If the
+	 * caller wants to clear it, he has to unset the boot_test flag
+	 * at runtime via sysfs to enable regular runtime testing
+	 */
+	if (boot)
+		return;
+
+	lrng_testing_reset(data);
+	atomic_set(&data->lrng_testing_enabled, 1);
+	pr_warn("Enabling data collection\n");
+}
+
+static void lrng_testing_fini(struct lrng_testing *data, u32 boot)
+{
+	/* If we have boot data, we do not reset yet to allow data to be read */
+	if (boot)
+		return;
+
+	atomic_set(&data->lrng_testing_enabled, 0);
+	lrng_testing_reset(data);
+	pr_warn("Disabling data collection\n");
+}
+
+static bool lrng_testing_store(struct lrng_testing *data, u32 value,
+			       u32 *boot)
+{
+	unsigned long flags;
+
+	if (!atomic_read(&data->lrng_testing_enabled) && (*boot != 1))
+		return false;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	/*
+	 * Disable entropy testing for boot time testing after ring buffer
+	 * is filled.
+	 */
+	if (*boot) {
+		if (((u32)atomic_read(&data->rb_writer)) >
+		    LRNG_TESTING_RINGBUFFER_SIZE) {
+			*boot = 2;
+			pr_warn_once("One time data collection test disabled\n");
+			spin_unlock_irqrestore(&data->lock, flags);
+			return false;
+		}
+
+		if (atomic_read(&data->rb_writer) == 1)
+			pr_warn("One time data collection test enabled\n");
+	}
+
+	data->lrng_testing_rb[((u32)atomic_read(&data->rb_writer)) &
+			      LRNG_TESTING_RINGBUFFER_MASK] = value;
+	atomic_inc(&data->rb_writer);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+#ifndef LRNG_TESTING_USE_BUSYLOOP
+	if (wq_has_sleeper(&data->read_wait))
+		wake_up_interruptible(&data->read_wait);
+#endif
+
+	return true;
+}
+
+static bool lrng_testing_have_data(struct lrng_testing *data)
+{
+	return ((((u32)atomic_read(&data->rb_writer)) &
+		 LRNG_TESTING_RINGBUFFER_MASK) !=
+		 (data->rb_reader & LRNG_TESTING_RINGBUFFER_MASK));
+}
+
+static int lrng_testing_reader(struct lrng_testing *data, u32 *boot,
+			       u8 *outbuf, u32 outbuflen)
+{
+	unsigned long flags;
+	int collected_data = 0;
+
+	lrng_testing_init(data, *boot);
+
+	while (outbuflen) {
+		u32 writer = (u32)atomic_read(&data->rb_writer);
+
+		spin_lock_irqsave(&data->lock, flags);
+
+		/* We have no data or reached the writer. */
+		if (!writer || (writer == data->rb_reader)) {
+
+			spin_unlock_irqrestore(&data->lock, flags);
+
+			/*
+			 * Now we gathered all boot data, enable regular data
+			 * collection.
+			 */
+			if (*boot) {
+				*boot = 0;
+				goto out;
+			}
+
+#ifdef LRNG_TESTING_USE_BUSYLOOP
+			while (!lrng_testing_have_data(data))
+				;
+#else
+			wait_event_interruptible(data->read_wait,
+						 lrng_testing_have_data(data));
+#endif
+			if (signal_pending(current)) {
+				collected_data = -ERESTARTSYS;
+				goto out;
+			}
+
+			continue;
+		}
+
+		/* We copy out word-wise */
+		if (outbuflen < sizeof(u32)) {
+			spin_unlock_irqrestore(&data->lock, flags);
+			goto out;
+		}
+
+		memcpy(outbuf, &data->lrng_testing_rb[data->rb_reader],
+		       sizeof(u32));
+		data->rb_reader++;
+
+		spin_unlock_irqrestore(&data->lock, flags);
+
+		outbuf += sizeof(u32);
+		outbuflen -= sizeof(u32);
+		collected_data += sizeof(u32);
+	}
+
+out:
+	lrng_testing_fini(data, *boot);
+	return collected_data;
+}
+
+static int lrng_testing_extract_user(struct file *file, char __user *buf,
+				     size_t nbytes, loff_t *ppos,
+				     int (*reader)(u8 *outbuf, u32 outbuflen))
+{
+	u8 *tmp, *tmp_aligned;
+	int ret = 0, large_request = (nbytes > 256);
+
+	if (!nbytes)
+		return 0;
+
+	/*
+	 * The intention of this interface is for collecting at least
+	 * 1000 samples due to the SP800-90B requirements. So, we make no
+	 * effort in avoiding allocating more memory that actually needed
+	 * by the user. Hence, we allocate sufficient memory to always hold
+	 * that amount of data.
+	 */
+	tmp = kmalloc(LRNG_TESTING_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	tmp_aligned = PTR_ALIGN(tmp, sizeof(u32));
+
+	while (nbytes) {
+		int i;
+
+		if (large_request && need_resched()) {
+			if (signal_pending(current)) {
+				if (ret == 0)
+					ret = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+
+		i = min_t(int, nbytes, LRNG_TESTING_RINGBUFFER_SIZE);
+		i = reader(tmp_aligned, i);
+		if (i <= 0) {
+			if (i < 0)
+				ret = i;
+			break;
+		}
+		if (copy_to_user(buf, tmp_aligned, i)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		nbytes -= i;
+		buf += i;
+		ret += i;
+	}
+
+	kfree_sensitive(tmp);
+
+	if (ret > 0)
+		*ppos += ret;
+
+	return ret;
+}
+
+#endif /* CONFIG_LRNG_TESTING_RECORDING */
+
+/************* Raw High-Resolution IRQ Timer Entropy Data Handling ************/
+
+#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY
+
+static u32 boot_raw_hires_test = 0;
+module_param(boot_raw_hires_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_hires_test, "Enable gathering boot time high resolution timer entropy of the first IRQ entropy events");
+
+static struct lrng_testing lrng_raw_hires = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_hires.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_hires.read_wait)
+};
+
+bool lrng_raw_hires_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_hires, value, &boot_raw_hires_test);
+}
+
+static int lrng_raw_hires_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_hires, &boot_raw_hires_test,
+				   outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_hires_read(struct file *file, char __user *to,
+				   size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_hires_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_hires_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_hires_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */
+
+/********************* Raw Jiffies Entropy Data Handling **********************/
+
+#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY
+
+static u32 boot_raw_jiffies_test = 0;
+module_param(boot_raw_jiffies_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_jiffies_test, "Enable gathering boot time high resolution timer entropy of the first entropy events");
+
+static struct lrng_testing lrng_raw_jiffies = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_jiffies.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_jiffies.read_wait)
+};
+
+bool lrng_raw_jiffies_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_jiffies, value,
+				  &boot_raw_jiffies_test);
+}
+
+static int lrng_raw_jiffies_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_jiffies, &boot_raw_jiffies_test,
+				   outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_jiffies_read(struct file *file, char __user *to,
+				   size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_jiffies_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_jiffies_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_jiffies_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
+
+/************************** Raw IRQ Data Handling ****************************/
+
+#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY
+
+static u32 boot_raw_irq_test = 0;
+module_param(boot_raw_irq_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_irq_test, "Enable gathering boot time entropy of the first IRQ entropy events");
+
+static struct lrng_testing lrng_raw_irq = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_irq.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_irq.read_wait)
+};
+
+bool lrng_raw_irq_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_irq, value, &boot_raw_irq_test);
+}
+
+static int lrng_raw_irq_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_irq, &boot_raw_irq_test, outbuf,
+				   outbuflen);
+}
+
+static ssize_t lrng_raw_irq_read(struct file *file, char __user *to,
+				 size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_irq_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_irq_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_irq_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */
+
+/************************ Raw _RET_IP_ Data Handling **************************/
+
+#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY
+
+static u32 boot_raw_retip_test = 0;
+module_param(boot_raw_retip_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_retip_test, "Enable gathering boot time entropy of the first return instruction pointer entropy events");
+
+static struct lrng_testing lrng_raw_retip = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_retip.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_retip.read_wait)
+};
+
+bool lrng_raw_retip_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_retip, value, &boot_raw_retip_test);
+}
+
+static int lrng_raw_retip_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_retip, &boot_raw_retip_test,
+				   outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_retip_read(struct file *file, char __user *to,
+				   size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_retip_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_retip_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_retip_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */
+
+/********************** Raw IRQ register Data Handling ************************/
+
+#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY
+
+static u32 boot_raw_regs_test = 0;
+module_param(boot_raw_regs_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_regs_test, "Enable gathering boot time entropy of the first interrupt register entropy events");
+
+static struct lrng_testing lrng_raw_regs = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_regs.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_regs.read_wait)
+};
+
+bool lrng_raw_regs_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_regs, value, &boot_raw_regs_test);
+}
+
+static int lrng_raw_regs_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_regs, &boot_raw_regs_test,
+				   outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_regs_read(struct file *file, char __user *to,
+				  size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_regs_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_regs_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_regs_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */
+
+/********************** Raw Entropy Array Data Handling ***********************/
+
+#ifdef CONFIG_LRNG_RAW_ARRAY
+
+static u32 boot_raw_array = 0;
+module_param(boot_raw_array, uint, 0644);
+MODULE_PARM_DESC(boot_raw_array, "Enable gathering boot time raw noise array data of the first entropy events");
+
+static struct lrng_testing lrng_raw_array = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_array.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_array.read_wait)
+};
+
+bool lrng_raw_array_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_array, value, &boot_raw_array);
+}
+
+static int lrng_raw_array_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_array, &boot_raw_array, outbuf,
+				   outbuflen);
+}
+
+static ssize_t lrng_raw_array_read(struct file *file, char __user *to,
+				   size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_array_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_array_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_array_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_ARRAY */
+
+/******************** Interrupt Performance Data Handling *********************/
+
+#ifdef CONFIG_LRNG_IRQ_PERF
+
+static u32 boot_irq_perf = 0;
+module_param(boot_irq_perf, uint, 0644);
+MODULE_PARM_DESC(boot_irq_perf, "Enable gathering interrupt entropy source performance data");
+
+static struct lrng_testing lrng_irq_perf = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_irq_perf.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_irq_perf.read_wait)
+};
+
+bool lrng_perf_time(u32 start)
+{
+	return lrng_testing_store(&lrng_irq_perf, random_get_entropy() - start,
+				  &boot_irq_perf);
+}
+
+static int lrng_irq_perf_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_irq_perf, &boot_irq_perf, outbuf,
+				   outbuflen);
+}
+
+static ssize_t lrng_irq_perf_read(struct file *file, char __user *to,
+				  size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_irq_perf_reader);
+}
+
+static const struct file_operations lrng_irq_perf_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_irq_perf_read,
+};
+
+#endif /* CONFIG_LRNG_IRQ_PERF */
+
+/****** Raw High-Resolution Scheduler-based Timer Entropy Data Handling *******/
+
+#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY
+
+static u32 boot_raw_sched_hires_test = 0;
+module_param(boot_raw_sched_hires_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_sched_hires_test, "Enable gathering boot time high resolution timer entropy of the first Scheduler-based entropy events");
+
+static struct lrng_testing lrng_raw_sched_hires = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_hires.lock),
+	.read_wait =
+		__WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_hires.read_wait)
+};
+
+bool lrng_raw_sched_hires_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_sched_hires, value,
+				  &boot_raw_sched_hires_test);
+}
+
+static int lrng_raw_sched_hires_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_sched_hires,
+				   &boot_raw_sched_hires_test,
+				   outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_sched_hires_read(struct file *file, char __user *to,
+					 size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_sched_hires_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_sched_hires_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_sched_hires_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY */
+
+/******************** Interrupt Performance Data Handling *********************/
+
+#ifdef CONFIG_LRNG_SCHED_PERF
+
+static u32 boot_sched_perf = 0;
+module_param(boot_sched_perf, uint, 0644);
+MODULE_PARM_DESC(boot_sched_perf, "Enable gathering scheduler-based entropy source performance data");
+
+static struct lrng_testing lrng_sched_perf = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_sched_perf.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_sched_perf.read_wait)
+};
+
+bool lrng_sched_perf_time(u32 start)
+{
+	return lrng_testing_store(&lrng_sched_perf, random_get_entropy() - start,
+				  &boot_sched_perf);
+}
+
+static int lrng_sched_perf_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_sched_perf, &boot_sched_perf, outbuf,
+				   outbuflen);
+}
+
+static ssize_t lrng_sched_perf_read(struct file *file, char __user *to,
+				    size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_sched_perf_reader);
+}
+
+static const struct file_operations lrng_sched_perf_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_sched_perf_read,
+};
+
+#endif /* CONFIG_LRNG_SCHED_PERF */
+
+/*************** Raw Scheduler task_struct->pid Data Handling *****************/
+
+#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY
+
+static u32 boot_raw_sched_pid_test = 0;
+module_param(boot_raw_sched_pid_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_sched_pid_test, "Enable gathering boot time entropy of the first PIDs collected by the scheduler entropy source");
+
+static struct lrng_testing lrng_raw_sched_pid = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_pid.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_pid.read_wait)
+};
+
+bool lrng_raw_sched_pid_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_sched_pid, value,
+				  &boot_raw_sched_pid_test);
+}
+
+static int lrng_raw_sched_pid_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_sched_pid,
+				   &boot_raw_sched_pid_test, outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_sched_pid_read(struct file *file, char __user *to,
+				       size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_sched_pid_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_sched_pid_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_sched_pid_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_SCHED_PID_ENTROPY */
+
+
+/*********** Raw Scheduler task_struct->start_time Data Handling **************/
+
+#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY
+
+static u32 boot_raw_sched_starttime_test = 0;
+module_param(boot_raw_sched_starttime_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_sched_starttime_test, "Enable gathering boot time entropy of the first task start times collected by the scheduler entropy source");
+
+static struct lrng_testing lrng_raw_sched_starttime = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_starttime.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_starttime.read_wait)
+};
+
+bool lrng_raw_sched_starttime_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_sched_starttime, value,
+				  &boot_raw_sched_starttime_test);
+}
+
+static int lrng_raw_sched_starttime_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_sched_starttime,
+				   &boot_raw_sched_starttime_test, outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_sched_starttime_read(struct file *file, char __user *to,
+				       size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_sched_starttime_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_sched_starttime_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_sched_starttime_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY */
+
+/************** Raw Scheduler task_struct->nvcsw Data Handling ****************/
+
+#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY
+
+static u32 boot_raw_sched_nvcsw_test = 0;
+module_param(boot_raw_sched_nvcsw_test, uint, 0644);
+MODULE_PARM_DESC(boot_raw_sched_nvcsw_test, "Enable gathering boot time entropy of the first task context switch numbers collected by the scheduler entropy source");
+
+static struct lrng_testing lrng_raw_sched_nvcsw = {
+	.rb_reader = 0,
+	.rb_writer = ATOMIC_INIT(0),
+	.lock      = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_nvcsw.lock),
+	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_nvcsw.read_wait)
+};
+
+bool lrng_raw_sched_nvcsw_entropy_store(u32 value)
+{
+	return lrng_testing_store(&lrng_raw_sched_nvcsw, value,
+				  &boot_raw_sched_nvcsw_test);
+}
+
+static int lrng_raw_sched_nvcsw_entropy_reader(u8 *outbuf, u32 outbuflen)
+{
+	return lrng_testing_reader(&lrng_raw_sched_nvcsw,
+				   &boot_raw_sched_nvcsw_test, outbuf, outbuflen);
+}
+
+static ssize_t lrng_raw_sched_nvcsw_read(struct file *file, char __user *to,
+				       size_t count, loff_t *ppos)
+{
+	return lrng_testing_extract_user(file, to, count, ppos,
+					 lrng_raw_sched_nvcsw_entropy_reader);
+}
+
+static const struct file_operations lrng_raw_sched_nvcsw_fops = {
+	.owner = THIS_MODULE,
+	.read = lrng_raw_sched_nvcsw_read,
+};
+
+#endif /* CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY */
+
+/*********************************** ACVT ************************************/
+
+#ifdef CONFIG_LRNG_ACVT_HASH
+
+/* maximum amount of data to be hashed as defined by ACVP */
+#define LRNG_ACVT_MAX_SHA_MSG	(65536 >> 3)
+
+/*
+ * As we use static variables to store the data, it is clear that the
+ * test interface is only able to handle single threaded testing. This is
+ * considered to be sufficient for testing. If multi-threaded use of the
+ * ACVT test interface would be performed, the caller would get garbage
+ * but the kernel operation is unaffected by this.
+ */
+static u8 lrng_acvt_hash_data[LRNG_ACVT_MAX_SHA_MSG]
+						__aligned(LRNG_KCAPI_ALIGN);
+static atomic_t lrng_acvt_hash_data_size = ATOMIC_INIT(0);
+static u8 lrng_acvt_hash_digest[LRNG_ATOMIC_DIGEST_SIZE];
+
+static ssize_t lrng_acvt_hash_write(struct file *file, const char __user *buf,
+				    size_t nbytes, loff_t *ppos)
+{
+	if (nbytes > LRNG_ACVT_MAX_SHA_MSG)
+		return -EINVAL;
+
+	atomic_set(&lrng_acvt_hash_data_size, (int)nbytes);
+
+	return simple_write_to_buffer(lrng_acvt_hash_data,
+				      LRNG_ACVT_MAX_SHA_MSG, ppos, buf, nbytes);
+}
+
+static ssize_t lrng_acvt_hash_read(struct file *file, char __user *to,
+				   size_t count, loff_t *ppos)
+{
+	SHASH_DESC_ON_STACK(shash, NULL);
+	const struct lrng_hash_cb *hash_cb = &lrng_sha_hash_cb;
+	ssize_t ret;
+
+	if (count > LRNG_ATOMIC_DIGEST_SIZE)
+		return -EINVAL;
+
+	ret = hash_cb->hash_init(shash, NULL) ?:
+	      hash_cb->hash_update(shash, lrng_acvt_hash_data,
+				atomic_read_u32(&lrng_acvt_hash_data_size)) ?:
+	      hash_cb->hash_final(shash, lrng_acvt_hash_digest);
+	if (ret)
+		return ret;
+
+	return simple_read_from_buffer(to, count, ppos, lrng_acvt_hash_digest,
+				       sizeof(lrng_acvt_hash_digest));
+}
+
+static const struct file_operations lrng_acvt_hash_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.llseek = default_llseek,
+	.read = lrng_acvt_hash_read,
+	.write = lrng_acvt_hash_write,
+};
+
+#endif /* CONFIG_LRNG_ACVT_DRNG */
+
+/**************************************************************************
+ * Debugfs interface
+ **************************************************************************/
+
+static int __init lrng_raw_init(void)
+{
+	struct dentry *lrng_raw_debugfs_root;
+
+	lrng_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_hires", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_hires_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_jiffies", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_jiffies_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_irq", 0400, lrng_raw_debugfs_root,
+				   NULL, &lrng_raw_irq_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_retip", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_retip_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_regs", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_regs_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_ARRAY
+	debugfs_create_file_unsafe("lrng_raw_array", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_array_fops);
+#endif
+#ifdef CONFIG_LRNG_IRQ_PERF
+	debugfs_create_file_unsafe("lrng_irq_perf", 0400, lrng_raw_debugfs_root,
+				   NULL, &lrng_irq_perf_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_sched_hires", 0400,
+				   lrng_raw_debugfs_root,
+				   NULL, &lrng_raw_sched_hires_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_sched_pid", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_sched_pid_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_sched_starttime", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_sched_starttime_fops);
+#endif
+#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY
+	debugfs_create_file_unsafe("lrng_raw_sched_nvcsw", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_raw_sched_nvcsw_fops);
+#endif
+#ifdef CONFIG_LRNG_SCHED_PERF
+	debugfs_create_file_unsafe("lrng_sched_perf", 0400,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_sched_perf_fops);
+#endif
+#ifdef CONFIG_LRNG_ACVT_HASH
+	debugfs_create_file_unsafe("lrng_acvt_hash", 0600,
+				   lrng_raw_debugfs_root, NULL,
+				   &lrng_acvt_hash_fops);
+#endif
+
+	return 0;
+}
+
+module_init(lrng_raw_init);
