summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am34
-rw-r--r--src/Makefile.in794
-rw-r--r--src/cpuid-43.h181
-rw-r--r--src/havege.c785
-rw-r--r--src/havege.h308
-rw-r--r--src/havegecmd.c460
-rw-r--r--src/havegecmd.h103
-rw-r--r--src/havegecollect.c480
-rw-r--r--src/havegecollect.h215
-rw-r--r--src/haveged.c1008
-rw-r--r--src/haveged.h100
-rw-r--r--src/havegetest.c1030
-rw-r--r--src/havegetest.h225
-rw-r--r--src/havegetune.c926
-rw-r--r--src/havegetune.h121
-rw-r--r--src/oneiteration.h201
16 files changed, 6971 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..c507ea4
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,34 @@
+## Process this file with automake to produce Makefile.in.
+
+if ENABLE_BIN
+bin_PROGRAMS = haveged
+else
+sbin_PROGRAMS = haveged
+endif
+
+AM_CFLAGS=-Wall -Wextra -Wpedantic -I..
+
+####nolibtool_start##
+##haveged_SOURCES = haveged.c havege.c havegetune.c havegecollect.c havegetest.c havegecmd.c \
+## cpuid-43.h haveged.h havege.h havegetune.h havegecollect.h havegetest.h oneiteration.h \
+## havegecmd.h
+##
+##haveged_LDADD = @HA_LDFLAGS@
+####nolibtool_end##
+##libtool_start##
+lib_LTLIBRARIES = libhavege.la
+libhavege_la_CPPFLAGS =
+libhavege_la_LDFLAGS = -version-number @HAVEGE_LT_VERSION@
+libhavege_la_LIBADD = @HA_LDFLAGS@
+
+libhavege_la_SOURCES = havege.c havegetune.c havegecollect.c havegetest.c \
+ cpuid-43.h havege.h havegetune.h havegecollect.h havegetest.h oneiteration.h
+
+pkginclude_HEADERS = havege.h
+
+haveged_SOURCES = haveged.c haveged.h havegecmd.c havegecmd.h
+
+haveged_LDADD = @HA_LDFLAGS@ libhavege.la
+##libtool_end##
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..559af60
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,794 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@ENABLE_BIN_TRUE@bin_PROGRAMS = haveged$(EXEEXT)
+@ENABLE_BIN_FALSE@sbin_PROGRAMS = haveged$(EXEEXT)
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkginclude_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \
+ "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgincludedir)"
+PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libhavege_la_DEPENDENCIES =
+am_libhavege_la_OBJECTS = libhavege_la-havege.lo \
+ libhavege_la-havegetune.lo libhavege_la-havegecollect.lo \
+ libhavege_la-havegetest.lo
+libhavege_la_OBJECTS = $(am_libhavege_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libhavege_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libhavege_la_LDFLAGS) $(LDFLAGS) -o $@
+am_haveged_OBJECTS = haveged.$(OBJEXT) havegecmd.$(OBJEXT)
+haveged_OBJECTS = $(am_haveged_OBJECTS)
+haveged_DEPENDENCIES = libhavege.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__maybe_remake_depfiles =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libhavege_la_SOURCES) $(haveged_SOURCES)
+DIST_SOURCES = $(libhavege_la_SOURCES) $(haveged_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(pkginclude_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVEGE_LT_VERSION = @HAVEGE_LT_VERSION@
+HA_DISTRO = @HA_DISTRO@
+HA_LDFLAGS = @HA_LDFLAGS@
+HA_UNITD = @HA_UNITD@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CFLAGS = -Wall -Wextra -Wpedantic -I..
+
+####nolibtool_start##
+####nolibtool_end##
+lib_LTLIBRARIES = libhavege.la
+libhavege_la_CPPFLAGS =
+libhavege_la_LDFLAGS = -version-number @HAVEGE_LT_VERSION@
+libhavege_la_LIBADD = @HA_LDFLAGS@
+libhavege_la_SOURCES = havege.c havegetune.c havegecollect.c havegetest.c \
+ cpuid-43.h havege.h havegetune.h havegecollect.h havegetest.h oneiteration.h
+
+pkginclude_HEADERS = havege.h
+haveged_SOURCES = haveged.c haveged.h havegecmd.c havegecmd.h
+haveged_LDADD = @HA_LDFLAGS@ libhavege.la
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu --ignore-deps src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libhavege.la: $(libhavege_la_OBJECTS) $(libhavege_la_DEPENDENCIES) $(EXTRA_libhavege_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libhavege_la_LINK) -rpath $(libdir) $(libhavege_la_OBJECTS) $(libhavege_la_LIBADD) $(LIBS)
+
+haveged$(EXEEXT): $(haveged_OBJECTS) $(haveged_DEPENDENCIES) $(EXTRA_haveged_DEPENDENCIES)
+ @rm -f haveged$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(haveged_OBJECTS) $(haveged_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+.c.o:
+ $(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+ $(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+libhavege_la-havege.lo: havege.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhavege_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhavege_la-havege.lo `test -f 'havege.c' || echo '$(srcdir)/'`havege.c
+
+libhavege_la-havegetune.lo: havegetune.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhavege_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhavege_la-havegetune.lo `test -f 'havegetune.c' || echo '$(srcdir)/'`havegetune.c
+
+libhavege_la-havegecollect.lo: havegecollect.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhavege_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhavege_la-havegecollect.lo `test -f 'havegecollect.c' || echo '$(srcdir)/'`havegecollect.c
+
+libhavege_la-havegetest.lo: havegetest.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhavege_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhavege_la-havegetest.lo `test -f 'havegetest.c' || echo '$(srcdir)/'`havegetest.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgincludeHEADERS: $(pkginclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \
+ done
+
+uninstall-pkgincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \
+ install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-pkgincludeHEADERS uninstall-sbinPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-pdf install-pdf-am \
+ install-pkgincludeHEADERS install-ps install-ps-am \
+ install-sbinPROGRAMS install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-libLTLIBRARIES uninstall-pkgincludeHEADERS \
+ uninstall-sbinPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/cpuid-43.h b/src/cpuid-43.h
new file mode 100644
index 0000000..a9d90a6
--- /dev/null
+++ b/src/cpuid-43.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * Under Section 7 of GPL version 3, you are granted additional
+ * permissions described in the GCC Runtime Library Exception, version
+ * 3.1, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License and
+ * a copy of the GCC Runtime Library Exception along with this program;
+ * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/* %ecx */
+#define bit_SSE3 (1 << 0)
+#define bit_PCLMUL (1 << 1)
+#define bit_SSSE3 (1 << 9)
+#define bit_FMA (1 << 12)
+#define bit_CMPXCHG16B (1 << 13)
+#define bit_SSE4_1 (1 << 19)
+#define bit_SSE4_2 (1 << 20)
+#define bit_MOVBE (1 << 22)
+#define bit_POPCNT (1 << 23)
+#define bit_AES (1 << 25)
+#define bit_XSAVE (1 << 26)
+#define bit_OSXSAVE (1 << 27)
+#define bit_AVX (1 << 28)
+
+/* %edx */
+#define bit_CMPXCHG8B (1 << 8)
+#define bit_CMOV (1 << 15)
+#define bit_MMX (1 << 23)
+#define bit_FXSAVE (1 << 24)
+#define bit_SSE (1 << 25)
+#define bit_SSE2 (1 << 26)
+
+/* Extended Features */
+/* %ecx */
+#define bit_LAHF_LM (1 << 0)
+#define bit_ABM (1 << 5)
+#define bit_SSE4a (1 << 6)
+#define bit_XOP (1 << 11)
+#define bit_LWP (1 << 15)
+#define bit_FMA4 (1 << 16)
+
+/* %edx */
+#define bit_LM (1 << 29)
+#define bit_3DNOWP (1 << 30)
+#define bit_3DNOW (1 << 31)
+
+
+#if defined(__i386__) && defined(__PIC__)
+/* %ebx may be the PIC register. */
+#if __GNUC__ >= 3
+#define __cpuid(level, a, b, c, d) \
+ __asm__ ("xchg{l}\t{%%}ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchg{l}\t{%%}ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+
+#define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("xchg{l}\t{%%}ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchg{l}\t{%%}ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+#else
+/* Host GCCs older than 3.0 weren't supporting Intel asm syntax
+ nor alternatives in i386 code. */
+#define __cpuid(level, a, b, c, d) \
+ __asm__ ("xchgl\t%%ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchgl\t%%ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+
+#define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("xchgl\t%%ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchgl\t%%ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+#endif
+#else
+#define __cpuid(level, a, b, c, d) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+
+#define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+#endif
+
+/* Return highest supported input value for cpuid instruction. ext can
+ be either 0x0 or 0x8000000 to return highest supported value for
+ basic or extended cpuid information. Function returns 0 if cpuid
+ is not supported or whatever cpuid returns in eax register. If sig
+ pointer is non-null, then first four bytes of the signature
+ (as found in ebx register) are returned in location pointed by sig. */
+
+static __inline unsigned int
+__get_cpuid_max (unsigned int __ext, unsigned int *__sig)
+{
+ unsigned int __eax, __ebx, __ecx, __edx;
+
+#ifndef __x86_64__
+ /* See if we can use cpuid. On AMD64 we always can. */
+#if __GNUC__ >= 3
+ __asm__ ("pushf{l|d}\n\t"
+ "pushf{l|d}\n\t"
+ "pop{l}\t%0\n\t"
+ "mov{l}\t{%0, %1|%1, %0}\n\t"
+ "xor{l}\t{%2, %0|%0, %2}\n\t"
+ "push{l}\t%0\n\t"
+ "popf{l|d}\n\t"
+ "pushf{l|d}\n\t"
+ "pop{l}\t%0\n\t"
+ "popf{l|d}\n\t"
+ : "=&r" (__eax), "=&r" (__ebx)
+ : "i" (0x00200000));
+#else
+/* Host GCCs older than 3.0 weren't supporting Intel asm syntax
+ nor alternatives in i386 code. */
+ __asm__ ("pushfl\n\t"
+ "pushfl\n\t"
+ "popl\t%0\n\t"
+ "movl\t%0, %1\n\t"
+ "xorl\t%2, %0\n\t"
+ "pushl\t%0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl\t%0\n\t"
+ "popfl\n\t"
+ : "=&r" (__eax), "=&r" (__ebx)
+ : "i" (0x00200000));
+#endif
+
+ if (!((__eax ^ __ebx) & 0x00200000))
+ return 0;
+#endif
+
+ /* Host supports cpuid. Return highest supported cpuid input value. */
+ __cpuid (__ext, __eax, __ebx, __ecx, __edx);
+
+ if (__sig)
+ *__sig = __ebx;
+
+ return __eax;
+}
+
+/* Return cpuid data for requested cpuid level, as found in returned
+ eax, ebx, ecx and edx registers. The function checks if cpuid is
+ supported and returns 1 for valid cpuid information or 0 for
+ unsupported cpuid level. All pointers are required to be non-null. */
+
+static __inline int
+__get_cpuid (unsigned int __level,
+ unsigned int *__eax, unsigned int *__ebx,
+ unsigned int *__ecx, unsigned int *__edx)
+{
+ unsigned int __ext = __level & 0x80000000;
+
+ if (__get_cpuid_max (__ext, 0) < __level)
+ return 0;
+
+ __cpuid (__level, *__eax, *__ebx, *__ecx, *__edx);
+ return 1;
+}
diff --git a/src/havege.c b/src/havege.c
new file mode 100644
index 0000000..b0070d1
--- /dev/null
+++ b/src/havege.c
@@ -0,0 +1,785 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **
+ */
+/**
+ * This compile unit implements the havege algorithm as an inteface to
+ * either a single collector in the calling process or an interface to
+ * multiple collector processes (experimental).
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include "havegetest.h"
+#include "havegetune.h"
+/**
+ * The library version interface results in a pair of version definitions
+ * which must agree yet must also be string literals. No foolproof build
+ * mechanism could be devised to ensure this, so a run-time check was added
+ * instead - if the two definitions do not agree, the interface is diabled.
+ */
+#define INTERFACE_DISABLED() strcmp(PACKAGE_VERSION,HAVEGE_PREP_VERSION)
+
+#if NUMBER_CORES>1
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <semaphore.h>
+#include <sched.h>
+/**
+ * Collection thread directory
+ */
+typedef struct {
+ pid_t main; /* the main thread */
+ H_UINT exit_ct; /* shutdown counter */
+ H_UINT count; /* associated count */
+ H_UINT last; /* last output */
+ H_UINT *out; /* buffer pointer */
+ H_UINT fatal; /* fatal error in last */
+ sem_t flags[1]; /* thread signals */
+} H_THREAD;
+/**
+ * Local prototypes
+ */
+static int havege_exit(H_PTR h_ptr);
+static void havege_ipc(H_PTR h_ptr, H_UINT n, H_UINT sz);
+static int havege_rngChild(H_PTR h_ptr, H_UINT cNumber);
+static void havege_unipc(H_PTR h_ptr);
+#endif
+/**
+ * Main allocation
+ */
+#ifdef ONLINE_TESTS_ENABLE
+typedef struct {
+ struct h_anchor info; /* Application anchor */
+ HOST_CFG cfg; /* Runtime environment */
+ procShared std; /* Shared test data */
+} H_SETUP;
+
+static int testsConfigure(H_UINT *tot, H_UINT *run, char *options);
+static void testsStatus(procShared *tps, char *tot, char *prod);
+
+static void testReport(H_COLLECT * h_ctxt, H_UINT action, H_UINT prod, H_UINT state, H_UINT ct);
+static void testReportA(H_PTR h, procA *context);
+static void testReportB(H_PTR h, procB *context);
+
+#else
+typedef struct {
+ struct h_anchor info; /* Application anchor */
+ HOST_CFG cfg; /* Runtime environment */
+} H_SETUP;
+
+#endif
+/**
+ * Local prototypes
+ */
+static void havege_mute(const char *format, ...);
+/**
+ * Initialize the environment based upon the tuning survey. This includes,
+ * allocation the output buffer (in shared memory if mult-threaded) and
+ * fitting the collection code to the tuning inputs.
+ */
+H_PTR havege_create( /* RETURN: app state */
+ H_PARAMS *params) /* IN: input params */
+{
+ H_SETUP *anchor;
+ HOST_CFG *env;
+ H_PTR h = 0;
+ H_UINT n = params->nCores;
+ H_UINT sz = params->ioSz;
+
+ if (INTERFACE_DISABLED())
+ return NULL;
+ if (0 == n)
+ n = 1;
+ if (0 == sz)
+ sz = DEFAULT_BUFSZ;
+ anchor = (H_SETUP *)calloc(sizeof(H_SETUP),1);
+ if (NULL==anchor)
+ return h;
+ h = &anchor->info;
+ h->print_msg = params->msg_out==0? havege_mute : params->msg_out;
+ h->metering = params->metering;
+ env = &anchor->cfg;
+ havege_tune(env, params);
+ h->error = H_NOERR;
+ h->arch = ARCH;
+ h->inject = params->injection;
+ h->n_cores = n;
+ h->havege_opts = params->options;
+ h->i_collectSz = params->collectSize==0? NDSIZECOLLECT : params->collectSize;
+ h->i_readSz = sz;
+ h->tuneData = env;
+ h->cpu = &env->cpus[env->a_cpu];
+ h->instCache = &env->caches[env->i_tune];
+ h->dataCache = &env->caches[env->d_tune];
+#ifdef ONLINE_TESTS_ENABLE
+ {
+ static const H_UINT tests[5] = {B_RUN, A_RUN};
+
+ H_UINT tot=0,run=0;
+ H_UINT i, j;
+
+ procShared *tps = (procShared *)&anchor->std;
+ if (testsConfigure(&tot, &run, params->testSpec)) {
+ h->error = H_NOTESTSPEC;
+ return h;
+ }
+ for(i=j=0;i<2;i++)
+ if (0!=(tot & tests[i])) {
+ tps->testsUsed |= tests[i];
+ tps->totTests[j].action = tests[i];
+ tps->totTests[j++].options = tot;
+ }
+ for(i=j=0;i<2;i++)
+ if (0!=(run & tests[i])) {
+ tps->testsUsed |= tests[i];
+ tps->runTests[j].action = tests[i];
+ tps->runTests[j++].options = run;
+ }
+ testsStatus(tps, tps->totText, tps->prodText);
+ tps->report = testReport;
+ h->testData = tps;
+ if (havege_test(tps, params)) {
+ h->error = H_NOTESTMEM;
+ return h;
+ }
+ }
+#endif
+#if NUMBER_CORES>1
+ havege_ipc(h, n, sz);
+#else
+ h->io_buf = malloc(sz);
+ h->threads = NULL;
+#endif
+ if (NULL==h->io_buf) {
+ h->error = H_NOBUF;
+ return h;
+ }
+ havege_ndsetup(h);
+ return h;
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+void havege_reparent(
+ H_PTR hptr)
+{
+#if NUMBER_CORES>1
+ H_THREAD *t = (H_THREAD *)hptr->threads;
+ if (0 == t)
+ return; /* single-threaded */
+
+ t->main = getpid();
+#endif
+}
+#pragma GCC diagnostic pop
+
+/**
+ * Destructor. In a multi-collector build, this method should be called from a signal handler
+ * to avoid creating processes.
+ */
+void havege_destroy( /* RETURN: none */
+ H_PTR hptr) /* IN-OUT: app anchor */
+{
+ if (NULL != hptr) {
+ H_COLLECT *htemp;
+ void *temp;
+#if NUMBER_CORES>1
+ if (!havege_exit(hptr))
+ return; /* only main thread continues */
+#endif
+ if (0 != (temp=hptr->io_buf)) {
+ hptr->io_buf = 0;
+ free(temp);
+ }
+#ifdef ONLINE_TESTS_ENABLE
+ if (0 != (temp=hptr->testData)) {
+ double *g = ((procShared *)temp)->G;
+ hptr->testData = 0;
+ if (0 != g)
+ free(g);
+ }
+#endif
+ if (0 != (htemp=hptr->collector)) {
+ hptr->collector = 0;
+ havege_nddestroy(htemp);
+ }
+ free(hptr);
+ }
+}
+/**
+ * Read random words. In the single-collector case, input is read by the calling
+ * the collection method directly. In the multi-collector case, the request info is
+ * signaled to the collector last read and the caller waits for a completion signal.
+ */
+int havege_rng( /* RETURN: number words read */
+ H_PTR h, /* IN-OUT: app state */
+ H_UINT *buffer, /* OUT: read buffer */
+ H_UINT sz) /* IN: number words to read */
+{
+#if NUMBER_CORES>1
+ H_THREAD *t = (H_THREAD *) h->threads;
+
+ t->count = sz;
+ t->out = buffer;
+ if (0!=sem_post(&t->flags[t->last]))
+ h->error = H_NORQST;
+ else if (0!=sem_wait(&t->flags[h->n_cores]))
+ h->error = H_NOCOMP;
+ else if (H_NOERR != t->fatal)
+ h->error = t->fatal;
+#else
+ H_UINT i;
+
+ for(i=0;i<sz;i++)
+ buffer[i] = havege_ndread((H_COLLECT *)h->collector);
+ h->error = ((H_COLLECT *)h->collector)->havege_err;
+#endif
+ return h->error==(H_UINT)H_NOERR? (int) sz : -1;
+}
+/**
+ * Start the entropy collector.
+ */
+int havege_run( /* RETURN: NZ on failure */
+ H_PTR h) /* IN-OUT: app anchor */
+{
+ int i = 0;
+
+#if NUMBER_CORES>1
+ for(i = 0; i < h->n_cores;i++)
+ if (0 == havege_rngChild(h, i))
+ return 1;
+#else
+ if (NULL==(h->collector = havege_ndcreate(h, i)))
+ return 1;
+#endif
+ return 0;
+}
+/**
+ * Report concealed setup data
+ */
+void havege_status( /* RETURN: none */
+ H_PTR h_ptr, /* IN: app state */
+ H_STATUS h_sts) /* OUT: app state */
+{
+ if (0 != h_sts) {
+ HOST_CFG *en = (HOST_CFG *) (h_ptr->tuneData);
+ CACHE_INST *cd = (CACHE_INST *)(h_ptr->dataCache);
+ CACHE_INST *ci = (CACHE_INST *)(h_ptr->instCache);
+ CPU_INST *cp = (CPU_INST *) (h_ptr->cpu);
+ procShared *ps = (procShared *)(h_ptr->testData);
+
+ h_sts->version = HAVEGE_PREP_VERSION;
+ h_sts->buildOptions = en->buildOpts;
+ h_sts->cpuSources = en->cpuOpts;
+ h_sts->i_cacheSources = en->icacheOpts;
+ h_sts->d_cacheSources = en->dcacheOpts;
+ h_sts->vendor = cp->vendor;
+ h_sts->d_cache = cd->size;
+ h_sts->i_cache = ci->size;
+ h_sts->tot_tests = (0 != ps)? ps->totText :"";
+ h_sts->prod_tests = (0 != ps)? ps->prodText :"";
+ if (0 != ps) {
+ memcpy(h_sts->n_tests, ps->meters, (H_OLT_PROD_B_P+1) * sizeof(H_UINT));
+ h_sts->last_test8 = ps->lastCoron;
+ }
+ }
+}
+/**
+ * Standard status presetations
+ */
+int havege_status_dump( /* RETURN: output length */
+ H_PTR hptr, /* IN: app state */
+ H_SD_TOPIC topic, /* IN: presentation topic */
+ char *buf, /* OUT: output area */
+ size_t len) /* IN: size of buf */
+{
+ struct h_status status;
+ int n = 0;
+
+ if (buf != 0) {
+ *buf = 0;
+ len -= 1;
+ havege_status(hptr, &status);
+ switch(topic) {
+ case H_SD_TOPIC_BUILD:
+ n += snprintf(buf, len, "ver: %s; arch: %s; vend: %s; build: (%s); collect: %uK",
+ status.version,
+ hptr->arch,
+ status.vendor,
+ status.buildOptions,
+ hptr->i_collectSz/1024
+ );
+ break;
+ case H_SD_TOPIC_TUNE:
+ n += snprintf(buf, len, "cpu: (%s); data: %uK (%s); inst: %uK (%s); idx: %u/%u; sz: %u/%u",
+ status.cpuSources,
+ status.d_cache,
+ status.d_cacheSources,
+ status.i_cache,
+ status.i_cacheSources,
+ hptr->i_maxidx - hptr->i_idx, hptr->i_maxidx,
+ hptr->i_sz, hptr->i_maxsz
+ );
+ break;
+ case H_SD_TOPIC_TEST:
+ {
+ H_UINT m;
+
+ if (strlen(status.tot_tests)>0) {
+ n += snprintf(buf+n, len-n, "tot tests(%s): ", status.tot_tests);
+ if ((m = status.n_tests[ H_OLT_TOT_A_P] + status.n_tests[ H_OLT_TOT_A_F])>0)
+ n += snprintf(buf+n, len-n, "A:%u/%u ", status.n_tests[ H_OLT_TOT_A_P], m);
+ if ((m = status.n_tests[ H_OLT_TOT_B_P] + status.n_tests[ H_OLT_TOT_B_F])>0)
+ n += snprintf(buf+n, len, "B:%u/%u ", status.n_tests[ H_OLT_TOT_B_P], m);
+ }
+ if (strlen(status.prod_tests)>0) {
+ n += snprintf(buf+n, len-n, "continuous tests(%s): ", status.prod_tests);
+ if ((m = status.n_tests[ H_OLT_PROD_A_P] + status.n_tests[ H_OLT_PROD_A_F])>0)
+ n += snprintf(buf+n, len-n, "A:%u/%u ", status.n_tests[ H_OLT_PROD_A_P], m);
+ if ((m = status.n_tests[ H_OLT_PROD_B_P] + status.n_tests[ H_OLT_PROD_B_F])>0)
+ n += snprintf(buf+n, len, "B:%u/%u ", status.n_tests[ H_OLT_PROD_B_P], m);
+ }
+ if (n>0)
+ n += snprintf(buf+n, len-n, " last entropy estimate %g", status.last_test8);
+ }
+ break;
+ case H_SD_TOPIC_SUM:
+ {
+ char units[] = {'T', 'G', 'M', 'K', 0};
+ double factor = 1024.0 * 1024.0 * 1024.0 * 1024.0;
+ double sz = ((double)hptr->n_fills * hptr->i_collectSz) * sizeof(H_UINT);
+ int i;
+
+ for (i=0;0 != units[i];i++) {
+ if (sz >= factor)
+ break;
+ factor /= 1024.0;
+ }
+ n = snprintf(buf, len, "fills: %u, generated: %.4g %c bytes",
+ hptr->n_fills,
+ sz / factor,
+ units[i]
+ );
+ }
+ break;
+ }
+ }
+ return n;
+}
+/**
+ * Return-check library prep version. Calling havege_version() with a NULL version
+ * returns the definition of HAVEGE_PREP_VERSION used to build the library. Calling
+ * with HAVEGE_PREP_VERSION as the version checks if this headers definition is
+ * compatible with that of the library, returning NULL if the input is incompatible
+ * with the library.
+ */
+const char *havege_version(const char *version)
+{
+ if (INTERFACE_DISABLED())
+ return NULL;
+ /**
+ * Version check academic at the moment, but initial idea is to do a table
+ * lookup on the library version to get a pattern to match against the
+ * input version.
+ */
+ if (version) {
+ H_UINT l_interface=0, l_revision=0, l_age=0;
+ H_UINT p, p_interface, p_revision, p_patch;
+
+#ifdef HAVEGE_LIB_VERSION
+ sscanf(HAVEGE_LIB_VERSION, "%u:%u:%u", &l_interface, &l_revision, &l_age);
+#endif
+ (void)l_interface;(void)l_revision;(void)l_age;(void)p_patch; /* No check for now */
+
+ p = sscanf(version, "%u.%u.%u", &p_interface, &p_revision, &p_patch);
+ if (p!=3 || p_interface != 1 || p_revision != 9)
+ return NULL;
+ }
+ return HAVEGE_PREP_VERSION;
+}
+
+/**
+ * Place holder if output display not provided
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+static void havege_mute( /* RETURN: none */
+ const char *format, /* IN: printf format */
+ ...) /* IN: args */
+{
+ ;
+}
+#pragma GCC diagnostic pop
+
+#if NUMBER_CORES > 1
+/**
+ * Cleanup collector(s). In a multi-collector environment, need to kill
+ * children to avoid zombies.
+ */
+static int havege_exit( /* RETURN: NZ if child */
+ H_PTR h_ptr) /* IN: app state */
+{
+ H_THREAD *t = (H_THREAD *)h_ptr->threads;
+ pid_t p;
+ H_UINT i;
+
+ if (0 == t)
+ return 0; /* Must be main thread */
+ t->fatal = H_EXIT;
+ for(i=0;i<t->exit_ct;i++)
+ (void)sem_post(&t->flags[i]);
+ if (getpid() != t->main)
+ return 1;
+ do { /* Wait for children */
+ p = wait(NULL);
+ } while(p != -1 && errno != ECHILD);
+ for(i=0;i<t->exit_ct;i++)
+ (void)sem_destroy(&t->flags[i]);
+ if (i==h_ptr->n_cores)
+ (void)sem_destroy(&t->flags[i]);
+ havege_unipc(h_ptr); /* unmap memory */
+ return 0;
+}
+
+/**
+ * Initialize IPC mechanism. This consists of setting up a shared memory area
+ * containing the output buffer and the collection thread directory.
+ */
+static void havege_ipc( /* RETURN: None */
+ H_PTR h, /* IN: app state */
+ H_UINT n, /* IN: number of threads */
+ H_UINT sz) /* IN: size of buffer */
+{
+ void *m;
+ H_THREAD *t;
+ H_UINT m_sz;
+ int i;
+
+ if (n > NUMBER_CORES) {
+ h->error = H_NOCORES;
+ return;
+ }
+ m = mmap(NULL,
+ m_sz = sz + sizeof(H_THREAD) + n * sizeof(sem_t),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS,
+ 0,
+ 0);
+ if (m != MAP_FAILED) {
+ h->io_buf = m;
+ h->m_sz = m_sz;
+ t = (H_THREAD *)((char *) m + sz);
+ memset(t, 0, sizeof(H_THREAD));
+ t->main = getpid();
+ h->threads = t;
+ for(i=0;i<=n;i++)
+ if(sem_init(&t->flags[i],1,0) < 0) {
+ h->error = H_NOINIT;
+ break;
+ }
+ t->exit_ct = i;
+ }
+}
+/**
+ * Child harvester task. If task fails to start H_PTR::error will be set to reason.
+ * If task fails after start, H_THREAD::fatal will be set to the reason and a completion
+ * will be posted to prevent the main thread from hanging waiting for a response.
+ */
+static int havege_rngChild(/* RETURN: none */
+ H_PTR h_ptr, /* IN: app state */
+ H_UINT cNumber) /* IN: collector index */
+{
+ H_COLLECT *h_ctxt = 0;
+ H_THREAD *thds = (H_THREAD *) h_ptr->threads;
+ H_UINT cNext, i, r;
+ int pid;
+
+ switch(pid=fork()) {
+ case 0:
+ h_ctxt = havege_ndcreate(h_ptr, cNumber);
+ if (NULL != h_ctxt) {
+ cNext = (cNumber + 1) % h_ptr->n_cores;
+ while(1) {
+ if (0!=sem_wait(&thds->flags[cNumber])) {
+ thds->fatal = H_NOWAIT;
+ break;
+ }
+ if (H_NOERR != thds->fatal) {
+ havege_nddestroy(h_ctxt);
+ exit(0);
+ }
+ thds->last = cNumber;
+ r = h_ctxt->havege_szFill - h_ctxt->havege_nptr;
+ if (thds->count < r)
+ r = thds->count;
+ for(i=0;i<r;i++)
+ thds->out[i] = havege_ndread(h_ctxt);
+ thds->fatal = h_ctxt->havege_err;
+ if (0==(thds->count -= i)) {
+ if (0!=sem_post(&thds->flags[h_ptr->n_cores])) {
+ thds->fatal = H_NODONE;
+ break;
+ }
+ continue;
+ }
+ thds->out += i;
+ if (0!=sem_post(&thds->flags[cNext])) {
+ thds->fatal = H_NOPOST;
+ break;
+ }
+#ifdef HAVE_SCHED_YIELD
+ (void)sched_yield();
+#endif
+ (void)havege_ndread(h_ctxt);
+ h_ctxt->havege_nptr = 0;
+ }
+ havege_nddestroy(h_ctxt);
+ }
+ else thds->fatal = h_ptr->error; /* h_ptr is a copy!! */
+ (void)sem_post(&thds->flags[h_ptr->n_cores]); /* announce death! */
+ break;
+ case -1:
+ h_ptr->error = H_NOTASK;
+ }
+ return pid;
+}
+/**
+ * Unmap memory
+ */
+static void havege_unipc( /* RETURN: none */
+ H_PTR h_ptr) /* IN: app state */
+{
+ if (0 != h_ptr->m_sz) {
+ munmap(h_ptr->io_buf, h_ptr->m_sz);
+ h_ptr->io_buf = 0;
+ }
+
+}
+#endif
+#ifdef ONLINE_TESTS_ENABLE
+/**
+ * Interpret options string as settings. The option string consists of terms
+ * like "[t|c][a[1-8][w]|b[w]]".
+ */
+static int testsConfigure( /* RETURN: non-zero on error */
+ H_UINT *tot, /* OUT: tot test options */
+ H_UINT *run, /* OUT: run test options */
+ char *options) /* IN: option string */
+{
+ H_UINT section=0;
+ int c;
+
+ if (options==0)
+ options = DEFAULT_TEST_OPTIONS;
+ while(0 != (c = *options++)) {
+ switch(c) {
+ case 'T': case 't': /* tot test */
+ section = 't';
+ *tot = 0;
+ break;
+ case 'C': case 'c': /* production test */
+ section = 'c';
+ *run = 0;
+ break;
+ case 'A': case 'a':
+ if (!section) return 1;
+ c = atoi(options);
+ if (c >= 1 && c < 9) {
+ c = 1<<c;
+ options +=1;
+ }
+ else c = 0;
+ c |= A_RUN;
+ if (*options=='W' || *options=='w') {
+ c |= A_WARN;
+ options++;
+ }
+ if (section=='t')
+ *tot |= c;
+ else *run |= c;
+ break;
+ case 'B': case 'b':
+ if (!section) return 1;
+ c = B_RUN;
+ if (*options=='W' || *options=='w') {
+ c |= B_WARN;
+ options++;
+ }
+ if (section=='t')
+ *tot |= c;
+ else *run |= c;
+ break;
+ default:
+ return 1;
+ }
+ }
+ return 0;
+}
+/**
+ * Show test setup. Output strings are [A[N]][B]..
+ */
+static void testsStatus( /* RETURN: test config */
+ procShared *tps, /* IN: shared data */
+ char *tot, /* OUT: tot tests */
+ char *prod) /* OUT: production tests */
+{
+ procInst *p;
+ char *dst = tot;
+ H_UINT i, j, k, m;
+
+ *dst = *tot = 0;
+ p = tps->totTests;
+ for(i=0;i<2;i++,p = tps->runTests, dst = prod) {
+ for(j=0;j<2;j++,p++) {
+ switch(p->action) {
+ case A_RUN:
+ *dst++ = 'A';
+ if (0!=(m = p->options & A_CYCLE)) {
+ for(k=0;m>>=1 != 0;k++);
+ *dst++ = '0' + k;
+ }
+ if (0 != (p->options & A_WARN))
+ *dst++ = 'w';
+ break;
+ case B_RUN:
+ *dst++ = 'B';
+ if (0 != (p->options & B_WARN))
+ *dst++ = 'w';
+ break;
+ }
+ *dst = 0;
+ }
+ }
+}
+/**
+ * Reporting unit for tests
+ */
+static void testReport(
+ H_COLLECT * h_ctxt, /* IN-OUT: collector context */
+ H_UINT action, /* IN: A_RUN or B_RUN */
+ H_UINT prod, /* IN: 0==tot, else continuous */
+ H_UINT state, /* IN: state variable */
+ H_UINT ct) /* IN: bytes consumed */
+{
+ H_PTR h_ptr = (H_PTR)(h_ctxt->havege_app);
+ onlineTests *context = (onlineTests *) h_ctxt->havege_tests;
+ char *result;
+
+ switch(state) {
+ case TEST_DONE: result = "success"; break;
+ case TEST_RETRY: result = "retry"; break;
+ case TEST_IGNORE: result = "warning"; break;
+ default: result = "failure";
+ }
+ h_ptr->print_msg("AIS-31 %s procedure %s: %s %d bytes fill %d\n",
+ prod==0? "tot" : "continuous", action==A_RUN? "A":"B", result, ct, h_ptr->n_fills);
+ if (0 != (h_ptr->havege_opts & (H_DEBUG_OLTR|H_DEBUG_OLT)))
+ switch(action){
+ case A_RUN:
+ testReportA(h_ptr, context->pA);
+ break;
+ case B_RUN:
+ testReportB(h_ptr, context->pB);
+ break;
+ }
+}
+/**
+ * Reporting unit for procedure A. Results are 0-257*(1-[4 or 5])
+ */
+static void testReportA( /* RETURN: nothing */
+ H_PTR h_ptr, /* IN: application instance */
+ procA *p) /* IN: proc instance */
+{
+ static const char * pa_tests[6] = {"test0","test1","test2","test3","test4","test5"};
+
+ H_UINT ran[6],sum[6];
+ H_UINT ct, i, j, k;
+
+ for (i=0;i<6;i++)
+ ran[i] = sum[i] = 0;
+ for(i=0;i<p->testRun;i++){
+ ct = p->results[i].testResult;
+ j = ct>>8;
+ ran[j] += 1;
+ if (0==(ct & 0xff))
+ sum[j] += 1;
+ }
+ h_ptr->print_msg("procedure A: %s:%d/%d, %s:%d/%d, %s:%d/%d, %s:%d/%d, %s:%d/%d, %s:%d/%d\n",
+ pa_tests[0], sum[0], ran[0],
+ pa_tests[1], sum[1], ran[1],
+ pa_tests[2], sum[2], ran[2],
+ pa_tests[3], sum[3], ran[3],
+ pa_tests[4], sum[4], ran[4],
+ pa_tests[5], sum[5], ran[5]
+ );
+ for(i=k=0;i<p->testRun;i++){
+ ct = p->results[i].testResult;
+ j = ct>>8;
+ if (j==1)
+ k+=1;
+ if (0!=(ct & 0xff))
+ h_ptr->print_msg(" %s[%d] failed with %d\n", pa_tests[j%6],k,p->results[i].finalValue);
+ }
+}
+/**
+ * Reporting unit for procedure B. Results are 6a-6b-7a[0]-7a[1]-7b[0]-7b[1]-7b[2]-7b[3]-8
+ */
+static void testReportB( /* RETURN: nothing */
+ H_PTR h_ptr, /* IN: application instance */
+ procB *p) /* IN: proc instance */
+{
+ static const char * pb_tests[5] = {"test6a","test6b","test7a","test7b","test8"};
+
+ H_UINT ct, i, j, ran[5],sum[5];
+
+ for (i=0;i<5;i++) {
+ ran[i] = sum[i] = 0;
+ }
+ for(i=0;i<p->testNbr;i++){
+ ct = p->results[i].testResult;
+ j = ct>>8;
+ ran[j] += 1;
+ if (0==(ct & 0xff))
+ sum[j] += 1;
+ }
+ h_ptr->print_msg("procedure B: %s:%d/%d, %s:%d/%d, %s:%d/%d, %s:%d/%d, %s:%d/%d\n",
+ pb_tests[0], sum[0], ran[0],
+ pb_tests[1], sum[1], ran[1],
+ pb_tests[2], sum[2], ran[2],
+ pb_tests[3], sum[3], ran[3],
+ pb_tests[4], sum[4], ran[4]
+ );
+ for(i=0;i<5;i++)
+ ran[i] = p->testNbr;
+ for(i=0;i<p->testNbr;i++){
+ ct = p->results[i].testResult;
+ j = ct>>8;
+ if (i < ran[j]) ran[j] = i;
+ if (0!=(ct & 0xff))
+ h_ptr->print_msg(" %s[%d] failed with %g\n", pb_tests[j],i-ran[j],p->results[i].finalValue);
+ }
+}
+#endif
+
diff --git a/src/havege.h b/src/havege.h
new file mode 100644
index 0000000..1483c69
--- /dev/null
+++ b/src/havege.h
@@ -0,0 +1,308 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HAVEGE_H
+#define HAVEGE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * header/package version as a numeric major, minor, patch triple. See havege_version()
+ * below for usage.
+ */
+#define HAVEGE_PREP_VERSION "1.9.14"
+/**
+ * Basic types
+ */
+#define H_UINT uint32_t
+#define H_UINT8 uint8_t
+/**
+ * Optional metering call-back. Called with event=0 at start of collection buffer fill.
+ * Called with event=1 at end of collection buffer fill. The nCollect parameter indicates
+ * the calling process if multiple collection processes are enabled. Use a value of 0
+ * to disable metering.
+ */
+typedef void (*pMeter)(H_UINT nCollect, H_UINT event);
+/**
+ * Optional message display call-back. This printf style method is used for all diagnostic
+ * output including havege_status(). Use a value of 0 to disable output.
+ */
+typedef void (*pMsg)(const char *format, ...);
+/**
+ * Injection call-back for RAW diagnostics. Use a value of 0 to disable diagnostic. Ignored
+ * except for diaqnotic builds.
+ */
+typedef int (*pRawIn)(volatile H_UINT *pData, H_UINT szData);
+/**
+ * options for H_PARAMS below. Lower byte transferred from verbose settings
+ * upper byte set by diagnositic run options
+ */
+#define H_VERBOSE 0x001 /* deprecated from ver 1.7 */
+#define H_DEBUG_INFO 0x001 /* Show config info, retries */
+#define H_DEBUG_OLTR 0x002 /* Show detailed test retry info */
+#define H_DEBUG_TIME 0x004 /* Show collection times */
+#define H_DEBUG_LOOP 0x008 /* Show loop parameters */
+#define H_DEBUG_COMPILE 0x010 /* Show assembly info */
+#define H_DEBUG_OLT 0x020 /* Show all test info */
+
+#define H_DEBUG_RAW_OUT 0x100 /* diagnostic output */
+#define H_DEBUG_RAW_IN 0x200 /* diagnostic input */
+#define H_DEBUG_TEST_IN 0x400 /* input test data */
+/**
+ * Initialization parameters. Use non-zero values to override default values.
+ * Notes:
+ *
+ * 1) Correspondence between provided value and value of H_PTR members are:
+ * ioSz <==> i_readSz, collectSize <==> i_collectSz, nCores <==> n_cores,
+ * options <==> havege_opts
+ * 2) ioSz is specified in bytes. collectSize sizes is specified as number
+ * of H_UINT. The default for ioSz is 1024*sizeof(H_UINT). The default
+ * for collecSize is 128K * sizeof(H_UINT).
+ * 3) The icacheSize and dcacheSize override cache sizes. Both are specified in KB.
+ * Either may be specified to override the tuning value. If both are provided,
+ * tuning code is bypassed. The fallback tuning values can be overridden
+ * by defining GENERIC_DCACHE and GENERIC_ICACHE (16 will be used if not
+ * otherwise defined)
+ * 4) null callback values suppress the function.
+ * 5) sysFs default is '/sys', procFs default is '/proc'.
+ * 6) testSpec same as haveged option "[t<x>][c<x>] x=[a[n][w]][b[w]]". If
+ * not specified (NULL) the default is "ta8b" - i.e. run the tot tests
+ */
+typedef struct {
+ H_UINT ioSz; /* size of write buffer */
+ H_UINT collectSize; /* size of collection buffer */
+ H_UINT icacheSize; /* Instruction cache size */
+ H_UINT dcacheSize; /* Data cache size */
+ H_UINT options; /* Other options */
+ H_UINT nCores; /* If multi-core */
+ pMeter metering; /* meterming method */
+ pMsg msg_out; /* output display method */
+ pRawIn injection; /* injection method */
+ char *procFs; /* proc mount point override */
+ char *sysFs; /* sys mount point override */
+ char *testSpec; /* test specification */
+} H_PARAMS;
+/**
+ * Status codes used in the error member of h_anchor
+ */
+typedef enum {
+ H_NOERR, /* 00 No error */
+ H_NOHANDLE, /* 01 No memory for handle */
+ H_NOBUF, /* 02 Output buffer allocation failed */
+ H_NOINIT, /* 03 semaphore init failed */
+ H_NOCOLLECT, /* 04 H_COLLECT allocation failed */
+ H_NOWALK, /* 05 Walk buffer allocation failed */
+ H_NOTESTSPEC, /* 06 invalid test specification */
+ H_NOTESTINIT, /* 07 test setup failed */
+ H_NOTESTMEM, /* 08 Unable to allocate test memory */
+ H_NOTESTTOT, /* 09 tot test failed */
+ H_NOTESTRUN, /* 10 production test failed */
+ H_NOCORES, /* 11 too many cores specified */
+ H_NOTASK, /* 12 Unable to create child task */
+ H_NOWAIT, /* 13 sem_wait failed */
+ H_NOPOST, /* 14 sem_post failed */
+ H_NODONE, /* 15 sem_post done failed */
+ H_NORQST, /* 16 sem_post request failed */
+ H_NOCOMP, /* 17 wait for completion failed */
+ H_EXIT, /* 18 Exit signal */
+ H_NOTIMER /* 19 timer failed */
+} H_ERR;
+/**
+ * Keep compiler honest
+ */
+typedef volatile void *H_VOL;
+/**
+ * Anchor for the RNG. Should be read only at devel level and above.
+ */
+typedef struct h_anchor {
+ H_UINT *io_buf; /* output buffer */
+ char *arch; /* "x86","sparc","ppc","ia64",etc */
+ void *cpu; /* information on the cpu */
+ void *instCache; /* instruction cache info */
+ void *dataCache; /* data cache info */
+ pMsg print_msg; /* output display method */
+ pMeter metering; /* metering method */
+ pRawIn inject; /* Injection diagnostic only */
+ H_VOL collector; /* single thread collector */
+ H_VOL threads; /* multi thread collectors */
+ void *testData; /* online test data */
+ void *tuneData; /* tuning data */
+ H_UINT error; /* H_ERR enum for status */
+ H_UINT havege_opts; /* option flags */
+ H_UINT i_maxidx; /* maximum instruction loop index */
+ H_UINT i_maxsz; /* maximum code size */
+ H_UINT i_idx; /* code index used */
+ H_UINT i_sz; /* code size used */
+ H_UINT i_collectSz; /* size of collection buffer */
+ H_UINT i_readSz; /* size of read buffer (bytes) */
+ H_UINT m_sz; /* size of thread ipc area (bytes) */
+ H_UINT n_cores; /* number of cores */
+ H_UINT n_fills; /* number of buffer fills */
+} *H_PTR;
+/**
+ * Fail/Success counters for tot and production tests.
+ */
+typedef enum {
+ H_OLT_TOT_A_F, /* tot Procedure A failed */
+ H_OLT_TOT_A_P, /* tot Procedure A passed */
+ H_OLT_TOT_B_F, /* tot Procedure B failed */
+ H_OLT_TOT_B_P, /* tot Procedure B passed */
+ H_OLT_PROD_A_F, /* prod Procedure A failed */
+ H_OLT_PROD_A_P, /* prod Procedure A passed */
+ H_OLT_PROD_B_F, /* prod Procedure B failed */
+ H_OLT_PROD_B_P /* prod Procedure B passed */
+} H_OLT_METERS;
+/**
+ * Structure used to query RNG anchor settings for information not exposed by
+ * H_PTR. List formats are strings with one or more tokens separated by space.
+ * Sources lists show how tuning parameters are derived. D is a build default,
+ * P is a run time override, items V* come from linux virtual file system,
+ * other items trace various cpuid sources. Tuning is skipped if both cache
+ * sizes have 'P' sources.
+ *
+ * Notes:
+ *
+ * 1) Build: package version of source
+ * 2) Build options: compiler version followed by build configuration encoded
+ * as string of: [C][I][M][T][V] where C=clock_gettime, I=tune with cpuid,
+ * M=multi-core, T=online-test, V=tune with vfs
+ * 3) Tuning source lists: D=default, P=parameter, C=cpuid present,
+ * H=hyperthreading, A=AMD cpuid, A5=AMD fn5, A6=AMD fn6, A8=AMD fn8
+ * L2=Intel has leaf2, L4=Intel has leaf4, B=Intel leaf b,
+ * 4=intel leaf4, V=virtual file system available
+ * VS=/sys/devices/system/cpu/cpu%d/cache/index<n>/level,
+ * VO=/sys/devices/system/cpu/online, VI=/proc/cpuinfo
+ * VC=/sys/devices/system/cpu
+ * 4) test spec [A[1..8]][B], see H_PARAMS above.
+ * 5) zero unless tests are enabled
+ * 6) Last Coron's entropy estimate from Procedure B, test 8
+ */
+typedef struct h_status {
+ const char *version; /* Package version [1] */
+ const char *buildOptions; /* Options [2] */
+ const char *vendor; /* cpuid machines only */
+ const char *cpuSources; /* Tuning sources list [3] */
+ const char *i_cacheSources; /* Tuning sources list [3] */
+ const char *d_cacheSources; /* Tuning sources list [3] */
+ const char *tot_tests; /* tot test spec [4] */
+ const char *prod_tests; /* prod test spec [4] */
+ H_UINT i_cache; /* size of L1 instruction cache KB */
+ H_UINT d_cache; /* size of L1 data cache KB */
+ H_UINT n_tests[H_OLT_PROD_B_P+1]; /* test statistics [5] */
+ double last_test8; /* last test8 result [6] */
+} *H_STATUS;
+/**
+ * Standard presentation formats for havege_status_dump.
+ */
+typedef enum {
+ H_SD_TOPIC_BUILD,
+/* ver: %s; arch: %s; vend: %s; build: (%s); collect: %dK */
+ H_SD_TOPIC_TUNE,
+/* cpu: (%s); data: %dK (%s); inst: %dK (%s); idx: %d/%d; sz: %d/%d */
+ H_SD_TOPIC_TEST,
+/* [tot tests (%s): A:%d/%d B: %d/%d;][continuous tests (%s): A:%d/%d B: %d/%d;][last entropy estimate %g] */
+ H_SD_TOPIC_SUM,
+/* fills: %d, generated: %.4g %c bytes */
+} H_SD_TOPIC;
+/**
+ * Public prototypes. Library users note that "havege_*" is reserved for library
+ * public functions. Note that the multi-core option is experimental and must
+ * enabled in the build.
+ */
+/**
+ * Create an anchor. The caller should check for a non-null return value with
+ * a error value of H_NOERR. Any non-null return should be disposed of by a
+ * call to havege_destroy() to free all allocated resources.
+ *
+ * Possible error values: H_NOERR, H_NOTESTSPEC, H_NOBUF, H_NOTESTMEM,
+ * H_NOINIT
+ */
+H_PTR havege_create(H_PARAMS *params);
+
+/**
+ * haveger_create() remembers parent pid and uses it to identify deallocating thread.
+ * daemonize() forks parent and effectively loses parent thread.
+ * havege_reparent(void) allows recovering new parent pid before havege_run() is started.
+ */
+void havege_reparent(H_PTR hptr);
+
+/**
+ * Frees all allocated anchor resources. If the multi-core option is used, this
+ * method should be called from a signal handler to prevent zombie processes.
+ * If called by the process that called haveged_create(), hptr will be freed
+ * when all child processes (if any) have terminated. If called by a child
+ * process, H_EXIT will be set and all children awakened to exit.
+ */
+void havege_destroy(H_PTR hptr);
+/**
+ * Read random words from an active anchor. The RNG must have been readied
+ * by a previous call to havege_run(). The read must take place within the
+ * allocated buffer, hptr->io_buf, and the range is specified in number of
+ * H_UINT to read. If the multi-core option is used, this buffer is
+ * memory-mapped between collectors.
+ *
+ * Returns the number of H_UINT read.
+ *
+ * Possible error values: H_NOERR, H_NOTESRUN, H_NOPOST, H_NODONE,
+ * H_NORQST, H_NOCOMP, H_EXIT
+ */
+int havege_rng(H_PTR hptr, H_UINT *buf, H_UINT sz);
+/**
+ * Warm up the RNG and run the start-up tests. The operation suceeded if the
+ * error member of the handle is H_NOERR. A failed handle should be disposed
+ * of by a call to havege_destroy().
+ *
+ * Returns non-zero on failure.
+ *
+ * Possible error values: H_NOERR, H_NOCOLLECT, H_NOWALK, H_NOTESTMEM,
+ * H_NOTASK, H_NOTESTTOT, H_NOWAIT,
+ * any havege_rng error
+ */
+int havege_run(H_PTR hptr);
+/**
+ * Fill in the h_status structure with read-only information collected from
+ * the package build, run-time tuning, and test components.
+ */
+void havege_status(H_PTR hptr, H_STATUS hsts);
+/**
+ * Call havege_status() and generate a standard presentation of H_STATUS content.
+ * See the H_SD_TOPIC enum above for the formats.
+ *
+ * Returns the number of bytes placed in buf.
+ */
+int havege_status_dump(H_PTR hptr, H_SD_TOPIC topic, char *buf, size_t len);
+/**
+ * Return/check library prep version. Calling havege_version() with a NULL version
+ * returns the definition of HAVEGE_PREP_VERSION used to build the library. Calling
+ * with HAVEGE_PREP_VERSION as the version checks if this headers definition is
+ * compatible with that of the library, returning NULL if the input is incompatible
+ * with the library.
+ */
+const char *havege_version(const char *version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/havegecmd.c b/src/havegecmd.c
new file mode 100644
index 0000000..9ced105
--- /dev/null
+++ b/src/havegecmd.c
@@ -0,0 +1,460 @@
+/**
+ ** Provide HAVEGE socket communication API
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2018 Werner Fink <werner@suse.de>
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifndef NO_COMMAND_MODE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#ifndef HAVE_STRUCT_UCRED
+struct ucred
+{
+ pid_t pid; /* PID of sending process. */
+ uid_t uid; /* UID of sending process. */
+ gid_t gid; /* GID of sending process. */
+};
+#endif
+
+#include "havegecmd.h"
+
+int first_byte;
+int socket_fd;
+static char errmsg[1024];
+
+static int new_root( /* RETURN: status */
+ const char *root, /* IN: path of the new root file system */
+ const volatile char *path, /* IN: path of the haveged executable */
+ char *const argv[], /* IN: arguments for the haveged process */
+ struct pparams *params) /* IN: input params */
+{
+ int ret;
+ struct stat st;
+ const char *realtive = (const char*)&path[0];
+
+ ret = chdir(root);
+ if (ret < 0) {
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't change to working directory %s: %s\n",
+ root, strerror(errno));
+ goto err;
+ }
+ if (path[0] == '/')
+ realtive++;
+ ret = fstatat(AT_FDCWD, realtive, &st, 0);
+ if (ret < 0) {
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't restart %s: %s\n",
+ path, strerror(errno));
+ goto err;
+ }
+ ret = chroot(".");
+ if (ret < 0) {
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't change root directory %s\n",
+ strerror(errno));
+ goto err;
+ }
+ ret = chdir("/");
+ if (ret < 0) {
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't change to working directory / : %s\n",
+ strerror(errno));
+ goto err;
+ }
+ ret = execv((const char *)path, argv);
+ if (ret < 0) {
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't restart %s: %s\n",
+ path, strerror(errno));
+ }
+err:
+ if (ret < 0)
+ print_msg("%s", errmsg);
+ return ret;
+}
+
+/**
+ * Open and listen on a UNIX socket to get command from there
+ */
+int cmd_listen( /* RETURN: UNIX socket file descriptor */
+ struct pparams *params) /* IN: input params */
+{
+ struct sockaddr_un su = { /* The abstract UNIX socket of haveged */
+ .sun_family = AF_UNIX,
+ .sun_path = HAVEGED_SOCKET_PATH,
+ };
+ const int one = 1;
+ int fd, ret;
+
+ fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (fd < 0) {
+ print_msg("%s: can not open UNIX socket\n", params->daemon);
+ goto err;
+ }
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, (socklen_t)sizeof(one));
+ if (ret < 0) {
+ close(fd);
+ fd = -1;
+ print_msg("%s: can not set option for UNIX socket\n", params->daemon);
+ goto err;
+ }
+
+ ret = bind(fd, (struct sockaddr *)&su, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(su.sun_path+1));
+ if (ret < 0) {
+ close(fd);
+ fd = -1;
+ if (errno != EADDRINUSE)
+ print_msg("%s: can not bind a name to UNIX socket\n", params->daemon);
+ else
+ fd = -2;
+ goto err;
+ }
+
+ ret = listen(fd, SOMAXCONN);
+ if (ret < 0) {
+ close(fd);
+ fd = -1;
+ print_msg("%s: can not listen on UNIX socket\n", params->daemon);
+ goto err;
+ }
+err:
+ return fd;
+}
+
+/**
+ * Open and connect on a UNIX socket to send command over this
+ */
+int cmd_connect( /* RETURN: UNIX socket file descriptor */
+ struct pparams *params) /* IN: input params */
+{
+ struct sockaddr_un su = { /* The abstract UNIX socket of haveged */
+ .sun_family = AF_UNIX,
+ .sun_path = HAVEGED_SOCKET_PATH,
+ };
+ const int one = 1;
+ int fd, ret;
+
+ fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (fd < 0) {
+ print_msg("%s: can not open UNIX socket\n", params->daemon);
+ goto err;
+ }
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, (socklen_t)sizeof(one));
+ if (ret < 0) {
+ print_msg("%s: can not set option for UNIX socket\n", params->daemon);
+ close(fd);
+ fd = -1;
+ goto err;
+ }
+
+ ret = connect(fd, (struct sockaddr *)&su, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(su.sun_path+1));
+ if (ret < 0) {
+ if (errno != ECONNREFUSED)
+ print_msg("%s: can not connect on UNIX socket\n", params->daemon);
+ close(fd);
+ fd = -1;
+ goto err;
+ }
+err:
+ return fd;
+}
+
+/**
+ * Handle arguments in command mode
+ */
+int getcmd( /* RETURN: success or error */
+ char *arg) /* handle current known commands */
+{
+ static const struct {
+ const char* cmd;
+ const int req;
+ const int arg;
+ const char* opt;
+ } cmds[] = {
+ { "root=", MAGIC_CHROOT, 1, NULL }, /* New root */
+ { "close", MAGIC_CLOSE, 0, NULL }, /* Close socket */
+ {0}
+ }, *cmd = cmds;
+ int ret = -1;
+
+ if (!arg || !*arg)
+ goto err;
+
+ optarg = NULL;
+ for (; cmd->cmd; cmd++)
+ if (cmd->arg) {
+ if (strncmp(cmd->cmd, arg, strlen(cmd->cmd)) == 0) {
+ optarg = strchr(arg, '=');
+ optarg++;
+ ret = cmd->req;
+ break;
+ }
+ }
+ else {
+ if (strcmp(cmd->cmd, arg) == 0) {
+ ret = cmd->req;
+ break;
+ }
+ }
+err:
+ return ret;
+}
+
+/**
+ * Handle incomming messages from socket
+ */
+int socket_handler( /* RETURN: closed file descriptor */
+ int fd, /* IN: connected socket file descriptor */
+ const volatile char *path, /* IN: path of the haveged executable */
+ char *const argv[], /* IN: arguments for the haveged process */
+ struct pparams *params) /* IN: input params */
+{
+ struct ucred cred = {0};
+ unsigned char magic[2], *ptr;
+ char *enqry;
+ char *optarg = NULL;
+ socklen_t clen;
+ int ret = -1, len;
+
+ if (fd < 0) {
+ print_msg("%s: no connection jet\n", params->daemon);
+ }
+
+ ptr = &magic[0];
+ len = sizeof(magic);
+ ret = safein(fd, ptr, len);
+ if (ret < 0) {
+ print_msg("%s: can not read from UNIX socket\n", params->daemon);
+ goto out;
+ }
+
+ if (magic[1] == '\002') { /* ASCII start of text: read argument provided */
+ uint32_t alen;
+
+ ret = receive_uinteger(fd, &alen);
+ if (ret < 0) {
+ print_msg("%s: can not read from UNIX socket\n", params->daemon);
+ goto out;
+ }
+
+ optarg = calloc(alen, sizeof(char));
+ if (!optarg) {
+ print_msg("can not allocate memory for message from UNIX socket");
+ goto out;
+ }
+ ptr = (unsigned char*)optarg;
+
+ ret = safein(fd, ptr, alen);
+ if (ret < 0) {
+ print_msg("%s: can not read from UNIX socket\n", params->daemon);
+ goto out;
+ }
+ }
+
+ clen = sizeof(struct ucred);
+ ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &clen);
+ if (ret < 0) {
+ print_msg("%s: can not get credentials from UNIX socket part1\n", params->daemon);
+ goto out;
+ }
+ if (clen != sizeof(struct ucred)) {
+ print_msg("%s: can not get credentials from UNIX socket part2\n", params->daemon);
+ goto out;
+ }
+ if (cred.uid != 0) {
+ enqry = ASCII_NAK;
+
+ ptr = (unsigned char *)enqry;
+ len = (int)strlen(enqry)+1;
+ safeout(fd, ptr, len);
+ }
+
+ switch (magic[0]) {
+ case MAGIC_CHROOT:
+ enqry = ASCII_ACK;
+
+ ret = new_root(optarg, path, argv, params);
+ if (ret < 0) {
+ uint32_t size = strlen(errmsg);
+ safeout(fd, ASCII_STX, strlen(ASCII_STX));
+ send_uinteger(fd, size);
+ safeout(fd, errmsg, size+1);
+ break;
+ }
+
+ ptr = (unsigned char *)enqry;
+ len = (int)strlen(enqry);
+ safeout(fd, ptr, len);
+
+ break;
+ case MAGIC_CLOSE:
+ enqry = ASCII_ACK;
+
+ close(socket_fd);
+ socket_fd = -1;
+
+ ptr = (unsigned char *)enqry;
+ len = (int)strlen(enqry);
+ safeout(fd, ptr, len);
+ argv[0][0] = first_byte;
+
+ break;
+ default:
+ enqry = ASCII_NAK;
+
+ ptr = (unsigned char *)enqry;
+ len = (int)strlen(enqry);
+ safeout(fd, ptr, len);
+ break;
+ }
+out:
+ if (optarg)
+ free(optarg);
+ if (fd > 0) {
+ close(fd);
+ fd = -1;
+ }
+ return fd;
+}
+
+/**
+ * Receive incomming messages from socket
+ */
+ssize_t safein( /* RETURN: read bytes */
+ int fd, /* IN: file descriptor */
+ void *ptr, /* OUT: pointer to buffer */
+ size_t len) /* IN: size of buffer */
+{
+ int saveerr = errno, avail;
+ ssize_t ret = 0;
+
+ if (len > SSIZE_MAX)
+ len = SSIZE_MAX;
+
+ ret = ioctl(fd, FIONREAD, &avail);
+ if (ret < 0 || avail <=0)
+ goto out;
+
+ if (len > (unsigned int) avail)
+ len = avail;
+
+ do {
+ errno = saveerr;
+ ssize_t p = recv(fd, ptr, len, 0 /* MSG_DONTWAIT */);
+ if (p < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+ print_msg("Unable to read from socket %d: %s", socket_fd, strerror(errno));
+ }
+ ptr = (char *) ptr + p;
+ ret += p;
+ len -= p;
+ }
+ while (len > 0);
+out:
+ return ret;
+}
+
+/**
+ * Send outgoing messages to socket
+ */
+void safeout( /* RETURN: nothing */
+ int fd, /* IN: file descriptor */
+ const void *ptr, /* IN: pointer to buffer */
+ size_t len) /* IN: size of buffer */
+{
+ int saveerr = errno;
+
+ do {
+ ssize_t p = send(fd, ptr, len, MSG_NOSIGNAL);
+ if (p < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EPIPE || errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+ print_msg("Unable to write to socket %d: %s", fd, strerror(errno));
+ }
+ ptr = (char *) ptr + p;
+ len -= p;
+ }
+ while (len > 0);
+
+ errno = saveerr;
+}
+
+/**
+ * Send outgoing unsigned integer to socket
+ */
+void send_uinteger( /* RETURN: nothing */
+ int fd, /* IN: file descriptor */
+ uint32_t value) /* IN: 32 bit unsigned integer */
+{
+ uint8_t buffer[4];
+
+ buffer[0] = (uint8_t)((value >> 24) & 0xFF);
+ buffer[1] = (uint8_t)((value >> 16) & 0xFF);
+ buffer[2] = (uint8_t)((value >> 8) & 0xFF);
+ buffer[3] = (uint8_t)((value >> 0) & 0xFF);
+
+ safeout(fd, buffer, 4 * sizeof(uint8_t));
+}
+
+/**
+ * Receive incomming unsigned integer from socket
+ */
+int receive_uinteger( /* RETURN: status */
+ int fd, /* IN: file descriptor */
+ uint32_t *value) /* OUT: 32 bit unsigned integer */
+{
+ uint8_t buffer[4];
+
+ if (safein(fd, buffer, 4 * sizeof(uint8_t)) < 0)
+ return -1;
+
+ *value = (((uint32_t)buffer[0]) << 24) |
+ (((uint32_t)buffer[1]) << 16) |
+ (((uint32_t)buffer[2]) << 8) |
+ (((uint32_t)buffer[3]) << 0);
+
+ return 0;
+}
+
+#endif
diff --git a/src/havegecmd.h b/src/havegecmd.h
new file mode 100644
index 0000000..19a1823
--- /dev/null
+++ b/src/havegecmd.h
@@ -0,0 +1,103 @@
+/**
+ ** Provide HAVEGE socket communication API
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2018 Werner Fink <werner@suse.de>
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **
+ */
+
+#ifndef HAVEGECMD_H
+#define HAVEGECMD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "havege.h"
+#include "haveged.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#define HAVEGED_SOCKET_PATH "\0/sys/entropy/haveged"
+#define MAGIC_CHROOT 'R'
+#define MAGIC_CLOSE 'X'
+#define MAGIC_PATH 'P'
+
+#define ASCII_ACK "\x6" /* ASCII acknowledge */
+#define ASCII_NAK "\x15" /* ASCII negative acknowledge */
+#define ASCII_STX "\x2" /* ASCII start of text */
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
+/**
+ * Open and listen on a UNIX socket to get command from there
+ */
+int cmd_listen(struct pparams *);
+
+/**
+ * Open and connect on a UNIX socket to send command over this
+ */
+int cmd_connect(struct pparams *);
+
+/**
+ * Handle arguments in command mode
+ */
+int getcmd(char *);
+
+/**
+ * Handle incomming messages from socket
+ */
+int socket_handler(int, const volatile char *, char *const [], struct pparams *);
+
+/**
+ * Receive incomming messages from socket
+ */
+ssize_t safein(int, void *, size_t);
+
+/**
+ * Send outgoing messages to socket
+ */
+void safeout(int, const void *, size_t);
+
+/**
+ * Send outgoing unsigned integer to socket
+ */
+void send_uinteger(int, uint32_t);
+
+/**
+ * Receive incomming unsigned integer from socket
+ */
+int receive_uinteger(int, uint32_t *);
+
+/**
+ * Socket file descriptor used for communication
+ */
+
+extern int socket_fd;
+extern int first_byte;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/havegecollect.c b/src/havegecollect.c
new file mode 100644
index 0000000..1c82e51
--- /dev/null
+++ b/src/havegecollect.c
@@ -0,0 +1,480 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * This compile unit isolates the operation of the HAVEGE algorithm to better
+ * deal with compiler issues. Extensive macro expansion used to deal with
+ * hardware variations.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "havegecollect.h"
+#include "havegetest.h"
+#include "havegetune.h"
+/**
+ * Injection and capture diagnostics
+ */
+#if defined(RAW_IN_ENABLE) || defined(RAW_OUT_ENABLE)
+#define DIAGNOSTICS_ENABLE
+#endif
+/**
+ * Option to use clockgettime() as timer source
+ */
+#if defined(ENABLE_CLOCK_GETTIME)
+#include <time.h>
+
+#undef HARDCLOCK
+#define HARDCLOCK(x) x = havege_clock()
+/**
+ * Provide a generic timer fallback
+ */
+static H_UINT havege_clock(void)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (H_UINT)(ts.tv_nsec + ts.tv_sec * 1000000000LL);
+}
+#endif
+
+/**
+ * Memory allocation sizing
+ */
+#define SZH_INIT sizeof(H_COLLECT)+sizeof(char *)*(LOOP_CT + 2)
+#define SZH_COLLECT(a) sizeof(H_COLLECT)+sizeof(H_UINT)*(a+16384-1)
+/**
+ * The HAVEGE collector is created by interleaving instructions generated by
+ * oneiteration.h with the LOOP() output to control the sequence. At each
+ * LOOP() point, the following actions are possible.
+ */
+typedef enum {
+ LOOP_NEXT, /* Next loop */
+ LOOP_ENTER, /* First loop */
+ LOOP_EXIT /* Last loop */
+} LOOP_BRANCH;
+/**
+ * The LOOP macro labels calculation sequences generated by oneiteration.h in
+ * decreasing order from LOOPCT down to 0. During a normal collection, the
+ * loop construct only introduces an extra conditional branch into the instruction
+ * stream. For the exceptional conditions (initialization, end-of-loop, and
+ * raw HARDCLOCK capture), the return from havege_cp() is used to determine
+ * the action to be taken.
+ */
+#define LOOP(n,m) loop##n: if (n < h_ctxt->havege_cdidx) { \
+ switch(havege_cp(h_ctxt,i,n,LOOP_PT(n))) { \
+ case LOOP_NEXT: goto loop##m; \
+ case LOOP_ENTER: goto loop_enter; \
+ case LOOP_EXIT: goto loop_exit; \
+ } \
+ }
+/**
+ * These macros below bind the code contained in oneiteration.h to the H_COLLECT
+ * instance defined above
+ */
+#define ANDPT (h_ctxt->havege_andpt)
+#define PTTEST (h_ctxt->havege_PTtest)
+#define PT (h_ctxt->havege_PT)
+#define PT1 (h_ctxt->havege_pt2)
+#define PT2 (h_ctxt->havege_PT2)
+#define PWALK (h_ctxt->havege_pwalk)
+#define RESULT (h_ctxt->havege_bigarray)
+/**
+ * Previous diagnostic support has been replaced. The new implementation provides
+ * simultaneous access to both the noise source (i.e. the timer tics) and the
+ * output. The tics buffer is also used by the injection diagnostic if enabled
+ */
+#ifdef DIAGNOSTICS_ENABLE
+#define HTICK1 (h_ctxt->havege_tics[i>>3])
+#define HTICK2 (h_ctxt->havege_tics[i>>3])
+#define SZ_TICK ((h_ptr->i_collectSz)>>3)
+#else
+#define HTICK1 (h_ctxt->havege_tic)
+#define HTICK2 (h_ctxt->havege_tic)
+#define SZ_TICK 0
+#endif
+
+/**
+ * If the injection diagnostic is enabled, use a wrapper for the timer source
+ */
+#ifdef RAW_IN_ENABLE
+static H_UINT havege_inject(H_COLLECT *h_ctxt, H_UINT x);
+
+#define HARDCLOCKR(x) x=havege_inject(h_ctxt, x)
+#else
+#define HARDCLOCKR(x) HARDCLOCK(x)
+#endif
+/**
+ * inline optimization - left conditional for legacy systems
+ */
+#if 0
+#define ROR32(value,shift) ((value >> (shift)) | (value << (32-shift)))
+#else
+inline static H_UINT ror32(const H_UINT value, const H_UINT shift) {
+ return (value >> shift) | (value << (32 - shift));
+}
+#define ROR32(value,shift) ror32(value, shift)
+#endif
+/**
+ * Local prototypes
+ */
+static LOOP_BRANCH havege_cp(H_COLLECT *h_ctxt, H_UINT i, H_UINT n, char *p);
+/**
+ * Protect the collection mechanism against ever-increasing gcc optimization
+ */
+#if defined (GCC_VERSION) && GCC_VERSION >= 40400
+static int havege_gather(H_COLLECT * h_ctxt) __attribute__((optimize(1)));
+#else
+static int havege_gather(H_COLLECT * h_ctxt);
+#endif
+static void havege_ndinit(H_PTR h_ptr, struct h_collect *h_ctxt);
+
+/**
+ * Create a collector
+ */
+H_COLLECT *havege_ndcreate(/* RETURN: NULL on failure */
+ H_PTR h_ptr, /* IN-OUT: application instance */
+ H_UINT nCollector) /* IN: The collector instance */
+{
+ H_UINT i,offs,*p,d_cache;
+ H_UINT szBuffer;
+ H_COLLECT *h_ctxt;
+
+ szBuffer = h_ptr->i_collectSz;
+ d_cache = ((CACHE_INST *)(h_ptr->dataCache))->size;
+ h_ctxt = (H_COLLECT *) calloc(SZH_COLLECT(szBuffer + SZ_TICK),1);
+ if (NULL != h_ctxt) {
+ h_ctxt->havege_app = h_ptr;
+ h_ctxt->havege_idx = nCollector;
+ h_ctxt->havege_raw = h_ptr->havege_opts & 0xff00;
+ h_ctxt->havege_rawInput = h_ptr->inject;
+ h_ctxt->havege_szCollect = szBuffer;
+ h_ctxt->havege_szFill = szBuffer>>3;
+ h_ctxt->havege_cdidx = h_ptr->i_idx;
+ p = (H_UINT *) RESULT;
+ h_ctxt->havege_err = H_NOERR;
+ h_ctxt->havege_tests = 0;
+ h_ctxt->havege_extra = 0;
+ h_ctxt->havege_tics = p+szBuffer;
+
+ /** An intermediate walk table twice the size of the L1 cache is allocated
+ ** for use in permuting time stamp readings. The is meant to exercise
+ ** processor TLBs.
+ */
+ ANDPT = ((2*d_cache*1024)/sizeof(H_UINT))-1;
+ p = (H_UINT *) calloc((ANDPT + 4097)*sizeof(H_UINT),1);
+ if (NULL != p) {
+ h_ctxt->havege_extra = p;
+ offs = (H_UINT)((((unsigned long)&p[4096])&0xfff)/sizeof(H_UINT));
+ PWALK = &p[4096-offs];
+ /**
+ * Warm up the generator, running the startup tests
+ */
+#if defined(RAW_IN_ENABLE)
+ if (0 == (h_ctxt->havege_raw & H_DEBUG_TEST_IN))
+#endif
+ {
+ H_UINT t0=0;
+
+ (void)havege_gather(h_ctxt); /* first sample */
+ t0 = HTICK1;
+ for(i=1;i<MININITRAND;i++)
+ (void)havege_gather(h_ctxt); /* warmup rng */
+ if (HTICK1==t0) { /* timer stuck? */
+ h_ptr->error = H_NOTIMER;
+ havege_nddestroy(h_ctxt);
+ return NULL;
+ }
+ }
+#ifdef ONLINE_TESTS_ENABLE
+ {
+ procShared *ps = (procShared *)(h_ptr->testData);
+ while(0!=ps->run(h_ctxt, 0)) { /* run tot tests */
+ (void)havege_gather(h_ctxt);
+ }
+ }
+ if (H_NOERR != (h_ptr->error = h_ctxt->havege_err)) {
+ havege_nddestroy(h_ctxt);
+ return NULL;
+ }
+#endif
+ h_ctxt->havege_nptr = szBuffer;
+ if (0 == (h_ctxt->havege_raw & H_DEBUG_RAW_OUT))
+ h_ctxt->havege_szFill = szBuffer;
+ }
+ else {
+ havege_nddestroy(h_ctxt);
+ h_ptr->error = H_NOWALK;
+ return NULL;
+ }
+ }
+ else h_ptr->error = H_NOCOLLECT;
+ return h_ctxt;
+}
+/**
+ * Destruct a collector
+ */
+void havege_nddestroy( /* RETURN: none */
+ H_COLLECT *h_ctxt) /* IN: collector context */
+{
+ if (0 != h_ctxt) {
+ if (h_ctxt->havege_extra!=0) {
+ free(h_ctxt->havege_extra);
+ h_ctxt->havege_extra = 0;
+ }
+ if (h_ctxt->havege_tests!=0) {
+ free(h_ctxt->havege_tests);
+ h_ctxt->havege_tests = 0;
+ }
+ free((void *)h_ctxt);
+ }
+}
+/**
+ * Read from the collector.
+ */
+H_UINT havege_ndread( /* RETURN: data value */
+ H_COLLECT *h_ctxt) /* IN: collector context */
+{
+ if (h_ctxt->havege_nptr >= h_ctxt->havege_szFill) {
+ H_PTR h_ptr = (H_PTR)(h_ctxt->havege_app);
+ pMeter pm;
+
+ if (0 != (pm = h_ptr->metering))
+ (*pm)(h_ctxt->havege_idx, 0);
+#ifdef ONLINE_TESTS_ENABLE
+ {
+ procShared *ps = (procShared *)(h_ptr->testData);
+ do {
+ (void) havege_gather(h_ctxt);
+ (void) ps->run(h_ctxt, 1);
+ } while(ps->discard(h_ctxt)>0);
+ }
+#else
+ (void) havege_gather(h_ctxt);
+#endif
+ h_ptr->n_fills += 1;
+ if (0 != pm)
+ (*pm)(h_ctxt->havege_idx, 1);
+ h_ctxt->havege_nptr = 0;
+ }
+#ifdef RAW_OUT_ENABLE
+ if (0!=(h_ctxt->havege_raw & H_DEBUG_RAW_OUT))
+ return h_ctxt->havege_tics[h_ctxt->havege_nptr++];
+#endif
+ return RESULT[h_ctxt->havege_nptr++];
+}
+/**
+ * Setup haveged
+ */
+void havege_ndsetup( /* RETURN: None */
+ H_PTR h_ptr) /* IN-OUT: application instance */
+{
+ char wkspc[SZH_INIT];
+
+ memset(wkspc, 0, SZH_INIT);
+ havege_ndinit(h_ptr, (struct h_collect *) wkspc);
+}
+/**
+ * This method is called only for control points NOT part of a normal collection:
+ *
+ * a) For a collection loop after all iterations are performed, this function
+ * determines if the collection buffer is full.
+ * b) For initialization, this method saves the address of the collection point
+ * for analysis at the end of the loop.
+ */
+static LOOP_BRANCH havege_cp( /* RETURN: branch to take */
+ H_COLLECT *h_ctxt, /* IN: collection context */
+ H_UINT i, /* IN: collection offset */
+ H_UINT n, /* IN: iteration index */
+ char *p) /* IN: code pointer */
+{
+
+ if (h_ctxt->havege_cdidx <= LOOP_CT)
+ return i < h_ctxt->havege_szCollect? LOOP_ENTER : LOOP_EXIT;
+ ((char **)RESULT)[n] = CODE_PT(p);
+ if (n==0) h_ctxt->havege_cdidx = 0;
+ return LOOP_NEXT;
+}
+
+/**
+ * The collection loop is constructed by repetitions of oneinteration.h interleaved
+ * with control points generated by the LOOP macro.
+ */
+static int havege_gather( /* RETURN: 1 if initialized */
+ H_COLLECT * h_ctxt) /* IN: collector context */
+{
+ H_UINT i=0,pt=0,inter=0;
+ H_UINT *Pt0, *Pt1, *Pt2, *Pt3, *Ptinter;
+
+#if defined(RAW_IN_ENABLE)
+if (0 != (h_ctxt->havege_raw & H_DEBUG_RAW_IN)) {
+ (*h_ctxt->havege_rawInput)(h_ctxt->havege_tics, h_ctxt->havege_szCollect>>3);
+ h_ctxt->havege_tic = h_ctxt->havege_tics[0];
+ }
+else if (0 != (h_ctxt->havege_raw & H_DEBUG_TEST_IN)) {
+ (*h_ctxt->havege_rawInput)(RESULT, h_ctxt->havege_szCollect);
+ return 1;
+ }
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+
+loop_enter:
+LOOP(40,39)
+ #include "oneiteration.h"
+LOOP(39,38)
+ #include "oneiteration.h"
+LOOP(38,37)
+ #include "oneiteration.h"
+LOOP(37,36)
+ #include "oneiteration.h"
+LOOP(36,35)
+ #include "oneiteration.h"
+LOOP(35,34)
+ #include "oneiteration.h"
+LOOP(34,33)
+ #include "oneiteration.h"
+LOOP(33,32)
+ #include "oneiteration.h"
+LOOP(32,31)
+ #include "oneiteration.h"
+LOOP(31,30)
+ #include "oneiteration.h"
+LOOP(30,29)
+ #include "oneiteration.h"
+LOOP(29,28)
+ #include "oneiteration.h"
+LOOP(28,27)
+ #include "oneiteration.h"
+LOOP(27,26)
+ #include "oneiteration.h"
+LOOP(26,25)
+ #include "oneiteration.h"
+LOOP(25,24)
+ #include "oneiteration.h"
+LOOP(24,23)
+ #include "oneiteration.h"
+LOOP(23,22)
+ #include "oneiteration.h"
+LOOP(22,21)
+ #include "oneiteration.h"
+LOOP(21,20)
+ #include "oneiteration.h"
+LOOP(20,19)
+ #include "oneiteration.h"
+LOOP(19,18)
+ #include "oneiteration.h"
+LOOP(18,17)
+ #include "oneiteration.h"
+LOOP(17,16)
+ #include "oneiteration.h"
+LOOP(16,15)
+ #include "oneiteration.h"
+LOOP(15,14)
+ #include "oneiteration.h"
+LOOP(14,13)
+ #include "oneiteration.h"
+LOOP(13,12)
+ #include "oneiteration.h"
+LOOP(12,11)
+ #include "oneiteration.h"
+LOOP(11,10)
+ #include "oneiteration.h"
+LOOP(10,9)
+ #include "oneiteration.h"
+LOOP(9,8)
+ #include "oneiteration.h"
+LOOP(8,7)
+ #include "oneiteration.h"
+LOOP(7,6)
+ #include "oneiteration.h"
+LOOP(6,5)
+ #include "oneiteration.h"
+LOOP(5,4)
+ #include "oneiteration.h"
+LOOP(4,3)
+ #include "oneiteration.h"
+LOOP(3,2)
+ #include "oneiteration.h"
+LOOP(2,1)
+ #include "oneiteration.h"
+LOOP(1,0)
+ #include "oneiteration.h"
+LOOP(0,0)
+ (void)havege_cp(h_ctxt, i,0,LOOP_PT(0));
+#pragma GCC diagnostic pop
+
+loop_exit:
+ return ANDPT==0? 0 : 1;
+}
+#ifdef RAW_IN_ENABLE
+/**
+ * Wrapper for noise injector. When input is injected, the hardclock
+ * call is not made and the contents of the tic buffer are used
+ * unchanged from when the inject call was made at the top of the
+ * loop.
+ */
+static H_UINT havege_inject( /* RETURN: clock value */
+ H_COLLECT *h_ctxt, /* IN: workspace */
+ H_UINT x) /* IN: injected value */
+{
+ if (0==(h_ctxt->havege_raw & H_DEBUG_RAW_IN)) {
+ HARDCLOCK(x);
+ }
+ return x;
+}
+#endif
+/**
+ * Initialize the collection loop
+ */
+#if defined (GCC_VERSION) && GCC_VERSION >= 40600
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+
+static void havege_ndinit( /* RETURN: None */
+ H_PTR h_ptr, /* IN-OUT: application instance */
+ struct h_collect *h_ctxt) /* IN: workspace */
+{
+ char **addr = (char **)(&RESULT[0]);
+ H_UINT sz;
+ int i;
+
+ h_ctxt->havege_cdidx = LOOP_CT + 1;
+ (void)havege_gather(h_ctxt);
+ for (i=0;i<=LOOP_CT;i++) {
+ if (0 != (h_ptr->havege_opts & H_DEBUG_COMPILE)) {
+ h_ptr->print_msg("Address %u=%p\n", i, addr[i]);
+ }
+ RESULT[i] = labs(addr[i] - addr[LOOP_CT]);
+ if (i > 0 && 0 != (h_ptr->havege_opts & H_DEBUG_LOOP)) {
+ h_ptr->print_msg("Loop %u: offset=%u, delta=%u\n", i,RESULT[i],RESULT[i-1]-RESULT[i]);
+ }
+ }
+ h_ptr->i_maxidx = LOOP_CT;
+ h_ptr->i_maxsz = RESULT[1];
+ sz = ((CACHE_INST *)(h_ptr->instCache))->size * 1024;
+ for(i=LOOP_CT;i>0;i--)
+ if (RESULT[i]>sz)
+ break;
+ h_ptr->i_idx = ++i;
+ h_ptr->i_sz = RESULT[i];
+}
diff --git a/src/havegecollect.h b/src/havegecollect.h
new file mode 100644
index 0000000..55ffbfb
--- /dev/null
+++ b/src/havegecollect.h
@@ -0,0 +1,215 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HAVEGECOLLECT_H
+#define HAVEGECOLLECT_H
+/**
+ ** Definitions needed to build haveged
+ */
+#include "havege.h"
+/**
+ * The collection context
+ */
+typedef struct h_collect {
+ void *havege_app; /* Application block */
+ H_UINT havege_idx; /* Identifer */
+ H_UINT havege_szCollect; /* Size of collection buffer */
+ H_UINT havege_raw; /* RAW mode control flags */
+ H_UINT havege_szFill; /* Fill size */
+ H_UINT havege_nptr; /* Input pointer */
+ pRawIn havege_rawInput; /* Injection function */
+ pRawIn havege_testInput; /* Injection function for test */
+ H_UINT havege_cdidx; /* normal mode control flags */
+ H_UINT *havege_pwalk; /* Instance variable */
+ H_UINT havege_andpt; /* Instance variable */
+ H_UINT havege_PT; /* Instance variable */
+ H_UINT havege_PT2; /* Instance variable */
+ H_UINT havege_pt2; /* Instance variable */
+ H_UINT havege_PTtest; /* Instance variable */
+ H_UINT havege_tic; /* Instance variable */
+ H_UINT *havege_tics; /* loop timer noise buffer */
+ H_UINT havege_err; /* H_ERR enum for status */
+ void *havege_tests; /* opague test context */
+ void *havege_extra; /* other allocations */
+ H_UINT havege_bigarray[1]; /* collection buffer */
+} volatile H_COLLECT;
+/**
+ ** Compiler intrinsics are used to make the build more portable and stable
+ ** with fall-backs provided where the intrisics cannot be used.
+ */
+#ifdef __GNUC__
+/* ################################################################################# */
+
+/**
+ ** For the GNU compiler, the use of a cpuid intrinsic is somewhat garbled by the
+ ** fact that some distributions (Centos 5.x) carry an empty cpuid.h (in order
+ ** to back patch glicb?). AFAIK cpuid did not appear in gcc until version 4.3
+ ** although it was in existence before. If we do not have a valid cpuid.h,
+ ** we provide our own copy of the file (from gcc 4.3)
+ **
+ ** Also, gcc 4.4 and later provide an optimize attribute which remedies the
+ ** effect ever increasing optimization on the collection loop
+ */
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+
+#define ASM __asm__ volatile
+/**
+ ** For the intel world...
+ */
+#ifdef HAVE_ISA_X86
+#define ARCH "x86"
+
+#if GCC_VERSION<40300
+#undef HAVE_CPUID_H
+#endif
+#ifdef HAVE_CPUID_H
+#include <cpuid.h>
+#else
+#include "cpuid-43.h"
+#endif
+/**
+ ** Compatibility wrappers
+ */
+#define CPUID(level,p)\
+ {\
+ register int ecx asm ("ecx") = p[2];\
+ __cpuid(level,p[0],p[1],p[2],p[3]);\
+ (void) ecx;\
+ }
+#define HASCPUID(p) __get_cpuid_max(0, p)
+/**
+ ** The rdtsc intrinsic is called in by x86intrin.h - also a recent gcc innovation
+ ** There have been some discussions of the code in 4.5 and 4.6, so you may opt
+ ** to use the inline alternative based on GCC_VERSION
+ */
+#ifdef HAVE_X86INTRIN_H
+#include <x86intrin.h>
+#endif
+#ifdef HAVE___RDTSC
+#define HARDCLOCK(x) x=__rdtsc()
+#else
+#define HARDCLOCK(x) ASM("rdtsc;movl %%eax,%0":"=m"(x)::"ax","dx")
+#endif
+#else
+/**
+ * Outside the x86 family
+ */
+#ifdef HAVE_ISA_GENERIC
+#define ARCH "generic"
+#define ENABLE_CLOCKGETTIME 1
+#endif
+
+#ifdef HAVE_ISA_IA64
+#define ARCH "ia64"
+#define HARDCLOCK(x) ASM("mov %0=ar.itc" : "=r"(x))
+#endif
+
+#ifdef HAVE_ISA_SPARC
+#define ARCH "sparc"
+#define HARDCLOCK(x) ASM("rd %%tick, %0":"=r"(x):"r"(x))
+#endif
+
+#ifdef HAVE_ISA_SPARCLITE
+#define ARCH "sparclite"
+#define HARDCLOCK(x) ASM(".byte 0x83, 0x41, 0x00, 0x00");\
+ ASM("mov %%g1, %0" : "=r"(x))
+#endif
+
+#ifdef HAVE_ISA_PPC
+#define ARCH "ppc"
+#define HARDCLOCK(x) ASM("mftb %0":"=r"(x)) /* eq. to mftb %0, 268 */
+#endif
+
+#ifdef HAVE_ISA_S390
+#define ARCH "s390"
+#define HARDCLOCK(x) { unsigned long long tsc; ASM("stck %0":"=Q"(tsc)::"cc"); x = (unsigned int)tsc; }
+#endif
+/**
+ * /Outside the x86 family
+ */
+#endif
+/**
+ * Use the "&&" extension to calculate the LOOP_PT
+ */
+#define CODE_PT(a) a
+#define LOOP_PT(a) &&loop##a
+
+/* ################################################################################# */
+#endif
+/**
+ * For the MSVC world
+ */
+#if _MSVC_VERS
+/* ################################################################################# */
+#define ARCH "x86"
+/**
+ * For the MSVC compilers V8 and above
+ */
+#include <intrin.h>
+/**
+ * Read the processor timestamp counter
+ */
+#define HARDCLOCK(x) x=__rdtsc()
+/**
+ * Normalize to the gcc interface
+ */
+#define CPUID(level,p) return __cpuidx(p, level, p[2])
+#define HASCPUID(p) \
+ { \
+ CPUID(0,a,b,c,d) \
+ }
+/**
+ * Use the __ReturnAddress intrinsic to calculate the LOOP_PT
+ */
+#define CODE_PT(a) __ReturnAddress()
+#define LOOP_PT(a) 0
+#endif
+/* ################################################################################# */
+/**
+ * Configuration defaults - allow override at compile
+ */
+#ifndef COLLECT_BUFSIZE
+#define COLLECT_BUFSIZE 128 /* collection buffer size in KW */
+#endif
+#ifndef GENERIC_DCACHE
+#define GENERIC_DCACHE 16 /* size of L1 data cache */
+#endif
+#ifndef GENERIC_ICACHE
+#define GENERIC_ICACHE 16 /* size of L1 instruction cache */
+#endif
+#ifndef LOOP_CT
+#define LOOP_CT 40 /* Max interations per collection loop */
+#endif
+/**
+ * Other useful definitions
+ */
+#define BITS_PER_H_UINT (8*sizeof(H_UINT)) /* Bit packing constant */
+#define DEFAULT_BUFSZ 1024*sizeof(H_UINT) /* Default for ioSz */
+#define MININITRAND 32 /* Number of initial fills to prime RNG */
+#define NDSIZECOLLECT (COLLECT_BUFSIZE*1024) /* Collection size: 128K*H_UINT = .5M byte */
+/**
+ ** The public collection interface
+ */
+H_COLLECT *havege_ndcreate(H_PTR hptr, H_UINT nCollector);
+void havege_nddestroy(H_COLLECT *rdr);
+H_UINT havege_ndread(H_COLLECT *rdr);
+void havege_ndsetup(H_PTR hptr);
+
+#endif
diff --git a/src/haveged.c b/src/haveged.c
new file mode 100644
index 0000000..b9cb77b
--- /dev/null
+++ b/src/haveged.c
@@ -0,0 +1,1008 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include <sys/auxv.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef NO_DAEMON
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#include <linux/random.h>
+#endif
+
+#ifndef NO_COMMAND_MODE
+#include "havegecmd.h"
+#include <limits.h>
+#endif
+
+#include <errno.h>
+#include "haveged.h"
+#include "havegecollect.h"
+/**
+ * stringize operators for maintainable text
+ */
+#define STRZ(a) #a
+#define SETTINGL(msg,val) STRZ(val) msg
+#define SETTINGR(msg,val) msg STRZ(val)
+
+// {{{ VERSION_TEXT
+static const char* VERSION_TEXT =
+ "haveged %s\n\n"
+ "Copyright (C) 2018-2021 Jirka Hladky <hladky.jiri@gmail.com>\n"
+ "Copyright (C) 2009-2014 Gary Wuertz <gary@issiweb.com>\n"
+ "Copyright (C) 2011-2012 BenEleventh Consulting <manolson@beneleventh.com>\n\n"
+ "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n";
+// }}} VERSION_TEXT
+
+/**
+ * Parameters
+ */
+static struct pparams defaults = {
+ .daemon = PACKAGE,
+ .exit_code = 1,
+ .setup = 0,
+ .ncores = 0,
+ .buffersz = 0,
+ .detached = 0,
+ .foreground = 0,
+ .d_cache = 0,
+ .i_cache = 0,
+ .run_level = 0,
+ .low_water = 0,
+ .tests_config = 0,
+ .os_rel = "/proc/sys/kernel/osrelease",
+ .pid_file = PID_DEFAULT,
+ .poolsize = "/proc/sys/kernel/random/poolsize",
+ .random_device = "/dev/random",
+ .sample_in = INPUT_DEFAULT,
+ .sample_out = OUTPUT_DEFAULT,
+ .verbose = 0,
+ .watermark = "/proc/sys/kernel/random/write_wakeup_threshold",
+ .command = 0
+ };
+struct pparams *params = &defaults;
+
+#ifdef RAW_IN_ENABLE
+FILE *fd_in;
+/**
+ * The injection diagnostic
+ */
+static int injectFile(volatile H_UINT *pData, H_UINT szData);
+#endif
+/**
+ * havege instance used by application
+ */
+static H_PTR handle = NULL;
+/**
+ * Local prototypes
+ */
+#ifndef NO_DAEMON
+static H_UINT poolSize = 0;
+
+static void daemonize(void);
+static int get_poolsize(void);
+static void run_daemon(H_PTR handle, const volatile char *path, char *const argv[]);
+static void set_watermark(int level);
+#endif
+
+static void anchor_info(H_PTR h);
+static int get_runsize(unsigned int *bufct, unsigned int *bufrem, char *bp);
+static char *ppSize(char *buffer, double sz);
+
+static void run_app(H_PTR handle, H_UINT bufct, H_UINT bufres);
+static void show_meterInfo(H_UINT id, H_UINT event);
+static void tidy_exit(int signum);
+static void usage(int db, int nopts, struct option *long_options, const char **cmds);
+
+static sigset_t mask, omask;
+
+#define ATOU(a) (unsigned int)atoi(a)
+/**
+ * Entry point
+ */
+int main(int argc, char **argv)
+{
+ volatile char *path = strdup(argv[0]);
+ volatile char *arg0 = argv[0];
+ if (path[0] != '/')
+ path = (char*)getauxval(AT_EXECFN);
+ static const char* cmds[] = {
+ "b", "buffer", "1", SETTINGR("Buffer size [KW], default: ",COLLECT_BUFSIZE),
+ "d", "data", "1", SETTINGR("Data cache size [KB], with fallback to: ", GENERIC_DCACHE ),
+#ifndef NO_COMMAND_MODE
+ "c", "command", "1", "Send a command mode to an already running haveged",
+#endif
+ "i", "inst", "1", SETTINGR("Instruction cache size [KB], with fallback to: ", GENERIC_ICACHE),
+ "f", "file", "1", "Sample output file, default: '" OUTPUT_DEFAULT "', '-' for stdout",
+ "F", "Foreground", "0", "Run daemon in foreground",
+ "r", "run", "1", "0=daemon, 1=config info, >1=<r>KB sample",
+ "n", "number", "1", "Output size in [k|m|g|t] bytes, 0 = unlimited to stdout",
+ "o", "onlinetest", "1", "[t<x>][c<x>] x=[a[n][w]][b[w]] 't'ot, 'c'ontinuous, default: ta8b",
+ "p", "pidfile", "1", "daemon pidfile, default: " PID_DEFAULT ,
+ "s", "source", "1", "Injection source file, default: '" INPUT_DEFAULT "', '-' for stdin",
+#if NUMBER_CORES>1
+ "t", "threads", "1", "Number of threads",
+#endif
+ "v", "verbose", "1", "Verbose mask 0=none,1=summary,2=retries,4=timing,8=loop,16=code,32=test",
+ "w", "write", "1", "Set write_wakeup_threshold [bits]",
+ "V", "version", "0", "Print version information and exit",
+ "h", "help", "0", "This help"
+ };
+ static int nopts = sizeof(cmds)/(4*sizeof(char *));
+ struct option long_options[nopts+1];
+ char short_options[1+nopts*2];
+ int c,i,j;
+ H_UINT bufct, bufrem, ierr;
+ H_PARAMS cmd;
+
+ if (havege_version(HAVEGE_PREP_VERSION)==NULL)
+ error_exit("version conflict %s!=%s", HAVEGE_PREP_VERSION, havege_version(NULL));
+#if NO_DAEMON==1
+ params->setup |= RUN_AS_APP;
+#endif
+#ifdef RAW_IN_ENABLE
+#define DIAG_USAGE2 SETTINGL("=inject ticks,", DIAG_RUN_INJECT)\
+ SETTINGL("=inject data", DIAG_RUN_TEST)
+
+ params->setup |= INJECT | RUN_AS_APP;
+#else
+#define DIAG_USAGE2 ""
+#endif
+#ifdef RAW_OUT_ENABLE
+#define DIAG_USAGE1 SETTINGL("=capture,", DIAG_RUN_CAPTURE)
+
+ params->setup |= CAPTURE | RUN_AS_APP;
+#else
+#define DIAG_USAGE1 ""
+#endif
+#if NUMBER_CORES>1
+ params->setup |= MULTI_CORE;
+#endif
+
+ first_byte = arg0[0];
+ if (access("/etc/initrd-release", F_OK) >= 0) {
+ arg0[0] = '@';
+ path[0] = '/';
+ }
+#ifdef SIGHUP
+ signal(SIGHUP, tidy_exit);
+#endif
+ signal(SIGINT, tidy_exit);
+ signal(SIGTERM, tidy_exit);
+#ifndef NO_COMMAND_MODE
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ sigemptyset(&mask);
+#ifdef SIGHUP
+ sigaddset(&mask, SIGHUP);
+#endif
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+#ifndef NO_COMMAND_MODE
+ sigaddset(&mask, SIGPIPE);
+#endif
+#if NUMBER_CORES>1
+ /* Hmmm ... currently the code does not use pthread_create(3) but fork(2) */
+ pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
+#else
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+#endif
+ strcpy(short_options,"");
+ bufct = bufrem = 0;
+ /**
+ * Build options
+ */
+ for(i=j=0;j<(nopts*4);j+=4) {
+ switch(cmds[j][0]) {
+ case 'o':
+#ifdef ONLINE_TESTS_ENABLE
+ break;
+#else
+ continue;
+#endif
+ case 'r':
+#if defined(RAW_IN_ENABLE) || defined (RAW_OUT_ENABLE)
+ if (0!=(params->setup & (INJECT|CAPTURE))) {
+ params->daemon = "havege_diagnostic";
+ cmds[j+3] = "run level, 0=diagnostic off,1=config info," DIAG_USAGE1 DIAG_USAGE2 ;
+ }
+ else
+#endif
+ if (0!=(params->setup & RUN_AS_APP))
+ continue;
+ break;
+ case 's':
+ if (0 == (params->setup & INJECT))
+ continue;
+ break;
+ case 't':
+ if (0 == (params->setup & MULTI_CORE))
+ continue;
+ break;
+ case 'p': case 'w': case 'F':
+ if (0 !=(params->setup & RUN_AS_APP))
+ continue;
+ break;
+ }
+ long_options[i].name = cmds[j+1];
+ long_options[i].has_arg = atoi(cmds[j+2]);
+ long_options[i].flag = NULL;
+ long_options[i].val = cmds[j][0];
+ strcat(short_options,cmds[j]);
+ if (long_options[i].has_arg!=0) strcat(short_options,":");
+ i += 1;
+ }
+ memset(&long_options[i], 0, sizeof(struct option));
+
+ do {
+ c = getopt_long (argc, argv, short_options, long_options, NULL);
+ switch(c) {
+ case 'F':
+ params->setup |= RUN_IN_FG;
+ params->foreground = 1;
+ break;
+ case 'b':
+ params->buffersz = ATOU(optarg) * 1024;
+ if (params->buffersz<4)
+ error_exit("invalid size %s", optarg);
+ break;
+#ifndef NO_COMMAND_MODE
+ case 'c':
+ params->command = optarg;
+ params->setup |= CMD_MODE;
+ break;
+#endif
+ case 'd':
+ params->d_cache = ATOU(optarg);
+ break;
+ case 'i':
+ params->i_cache = ATOU(optarg);
+ break;
+ case 'f':
+ params->sample_out = optarg;
+ if (strcmp(optarg,"-") == 0 )
+ params->setup |= USE_STDOUT;
+ break;
+ case 'n':
+ if (get_runsize(&bufct, &bufrem, optarg))
+ error_exit("invalid count: %s", optarg);
+ params->setup |= RUN_AS_APP|RANGE_SPEC;
+ if (bufct==0 && bufrem==0)
+ params->setup |= USE_STDOUT; /* ugly but documented behavior! */
+ break;
+ case 'o':
+ params->tests_config = optarg;
+ break;
+ case 'p':
+ params->pid_file = optarg;
+ break;
+ case 'r':
+ params->run_level = ATOU(optarg);
+ if (params->run_level != 0)
+ params->setup |= RUN_AS_APP;
+ break;
+ case 's':
+ params->sample_in = optarg;
+ break;
+ case 't':
+ params->ncores = ATOU(optarg);
+ if (params->ncores > NUMBER_CORES)
+ error_exit("invalid thread count: %s", optarg);
+ break;
+ case 'v':
+ params->verbose = ATOU(optarg);
+ break;
+ case 'w':
+ params->setup |= SET_LWM;
+ params->low_water = ATOU(optarg);
+ break;
+ case '?':
+ case 'h':
+ usage(0, nopts, long_options, cmds);
+ /* fallthrough */
+ case 'V':
+ printf(VERSION_TEXT, HAVEGE_PREP_VERSION);
+ exit(EXIT_SUCCESS);
+ case -1:
+ break;
+ }
+ } while (c!=-1);
+#ifndef NO_COMMAND_MODE
+ if (params->setup & CMD_MODE) {
+ int ret = 0, len;
+ uint32_t size;
+ char *ptr, answer[6], cmd[2];
+ fd_set read_fd;
+ sigset_t block;
+
+ socket_fd = cmd_connect(params);
+ if (socket_fd < 0) {
+ ret = -1;
+ goto err;
+ }
+ cmd[0] = getcmd(params->command);
+ if (cmd[0] < 0) {
+ ret = -1;
+ goto err;
+ }
+ cmd[1] = '\0';
+ switch (cmd[0]) {
+ char *root;
+ case MAGIC_CHROOT:
+ root = optarg;
+ size = (uint32_t)strlen(root)+1;
+ cmd[1] = '\002';
+ safeout(socket_fd, &cmd[0], 2);
+ send_uinteger(socket_fd, size);
+ safeout(socket_fd, root, size);
+ break;
+ case MAGIC_CLOSE:
+ ptr = &cmd[0];
+ len = (int)strlen(cmd)+1;
+ safeout(socket_fd, ptr, len);
+ break;
+ case '?':
+ default:
+ ret = -1;
+ break;
+ }
+ answer[0] = '\0';
+ ptr = &answer[0];
+
+ sigemptyset(&block);
+ sigaddset(&block, SIGPIPE);
+
+ FD_ZERO(&read_fd);
+ FD_SET(socket_fd, &read_fd);
+
+ do {
+ struct timeval two = {6, 0};
+ ret = select(socket_fd+1, &read_fd, NULL, NULL, &two);
+ if (ret >= 0) break;
+ if (errno != EINTR)
+ error_exit("Select error: %s", strerror(errno));
+ }
+ while (1);
+
+ ret = safein(socket_fd, ptr, 1);
+ if (ret < 0)
+ goto err;
+ switch (answer[0]) {
+ case '\002': {
+ char *msg;
+ ret = receive_uinteger(socket_fd, &size);
+ if (ret < 0)
+ goto err;
+ msg = calloc(size, sizeof(char));
+ if (!msg)
+ error_exit("can not allocate memory for message from UNIX socket: %s",
+ strerror(errno));
+ ret = safein(socket_fd, msg, size);
+ if (ret < 0)
+ goto err;
+ fprintf(stderr, "%s: %s", params->daemon, msg);
+ free(msg);
+ ret = -1;
+ }
+ break;
+ case '\x6':
+ ret = 0;
+ break;
+ case '\x15':
+ default:
+ ret = -1;
+ break;
+ }
+ err:
+ close(socket_fd);
+ return ret;
+ }
+ else {
+ socket_fd = cmd_listen(params);
+ if (socket_fd >= 0)
+ fprintf(stderr, "%s: command socket is listening at fd %d\n", params->daemon, socket_fd);
+ else {
+ if (socket_fd == -2) {
+ fprintf(stderr, "%s: command socket already in use\n", params->daemon);
+ error_exit("%s: please check if there is another instance of haveged running\n", params->daemon);
+ } else {
+ fprintf(stderr, "%s: can not initialize command socket: %s\n", params->daemon, strerror(errno));
+ fprintf(stderr, "%s: disabling command mode for this instance\n", params->daemon);
+ }
+ }
+ }
+#endif
+ if (params->tests_config == 0)
+ params->tests_config = (0 != (params->setup & RUN_AS_APP))? TESTS_DEFAULT_APP : TESTS_DEFAULT_RUN;
+ memset(&cmd, 0, sizeof(H_PARAMS));
+ cmd.collectSize = params->buffersz;
+ cmd.icacheSize = params->i_cache;
+ cmd.dcacheSize = params->d_cache;
+ cmd.options = params->verbose & 0xff;
+ cmd.nCores = params->ncores;
+ cmd.testSpec = params->tests_config;
+ cmd.msg_out = print_msg;
+ if (0 != (params->setup & RUN_AS_APP)) {
+ cmd.ioSz = APP_BUFF_SIZE * sizeof(H_UINT);
+ if (params->verbose!=0 && 0==(params->setup & RANGE_SPEC))
+ params->run_level = 1;
+ }
+#ifndef NO_DAEMON
+ else {
+ poolSize = get_poolsize();
+ i = (poolSize + 7)/8 * sizeof(H_UINT);
+ cmd.ioSz = sizeof(struct rand_pool_info) + i *sizeof(H_UINT);
+ }
+#endif
+ if (0 != (params->verbose & H_DEBUG_TIME))
+ cmd.metering = show_meterInfo;
+
+ if (0 !=(params->setup & CAPTURE) && 0 != (params->run_level == DIAG_RUN_CAPTURE))
+ cmd.options |= H_DEBUG_RAW_OUT;
+#ifdef RAW_IN_ENABLE
+ if (0 !=(params->setup & INJECT) && 0 != (params->run_level & (DIAG_RUN_INJECT|DIAG_RUN_TEST))) {
+ if (strcmp(params->sample_in,"-") == 0 )
+ fd_in = stdin;
+ else fd_in = fopen(params->sample_in, "rb");
+ if (NULL == fd_in)
+ error_exit("Unable to open: %s", params->sample_in);
+ cmd.injection = injectFile;
+ if (params->run_level==DIAG_RUN_INJECT)
+ cmd.options |= H_DEBUG_RAW_IN;
+ else if (params->run_level==DIAG_RUN_TEST)
+ cmd.options |= H_DEBUG_TEST_IN;
+ else usage(1, nopts, long_options, cmds);
+ }
+#endif
+ handle = havege_create(&cmd);
+ ierr = handle==NULL? H_NOHANDLE : handle->error;
+ switch(ierr) {
+ case H_NOERR:
+ break;
+ case H_NOTESTSPEC:
+ error_exit("unrecognized test setup: %s", cmd.testSpec);
+ break;
+ default:
+ error_exit("Couldn't initialize haveged (%d)", ierr);
+ }
+ if (0 != (params->setup & RUN_AS_APP)) {
+ if (params->run_level==1)
+ anchor_info(handle);
+ else if (0==(params->setup&(INJECT|CAPTURE))) {
+ /* must specify range with --number or --run > 1 but not both */
+ if (params->run_level>1) {
+ if (0==(params->setup&RANGE_SPEC)) { /* --run specified */
+ bufct = params->run_level/sizeof(H_UINT);
+ bufrem = (params->run_level%sizeof(H_UINT))*1024;
+ }
+ else usage(2, nopts, long_options, cmds); /* both specified */
+ }
+ else if (0==(params->setup&RANGE_SPEC))
+ usage(3,nopts, long_options, cmds); /* neither specified */
+ else if (0==(params->setup&USE_STDOUT)&&(bufct+bufrem)==0)
+ usage(4, nopts, long_options, cmds); /* only with stdout */
+ run_app(handle, bufct, bufrem);
+ }
+ else if (0==(params->setup&USE_STDOUT)&&(bufct+bufrem)==0)
+ usage(5, nopts, long_options, cmds); /* only with stdout */
+ else run_app(handle, bufct, bufrem);
+ }
+#ifndef NO_DAEMON
+ else run_daemon(handle, path, argv);
+#endif
+ havege_destroy(handle);
+ exit(0);
+}
+#ifndef NO_DAEMON
+/**
+ * The usual daemon setup
+ */
+static void daemonize( /* RETURN: nothing */
+ void) /* IN: nothing */
+{
+ FILE *fh;
+ openlog(params->daemon, LOG_CONS, LOG_DAEMON);
+ syslog(LOG_NOTICE, "%s starting up", params->daemon);
+ if (daemon(0, 0) == -1)
+ error_exit("Cannot fork into the background");
+ fh = fopen(params->pid_file, "w");
+ if (!fh)
+ error_exit("Couldn't open PID file \"%s\" for writing: %s.", params->pid_file, strerror(errno));
+ fprintf(fh, "%i", getpid());
+ fclose(fh);
+ params->detached = 1;
+}
+/**
+ * Get configured poolsize
+ */
+static int get_poolsize( /* RETURN: number of bits */
+ void) /* IN: nothing */
+{
+ FILE *poolsize_fh,*osrel_fh;
+ unsigned int major,minor;
+ int max_bits;
+
+ poolsize_fh = fopen(params->poolsize, "rb");
+ if (poolsize_fh) {
+ if (fscanf(poolsize_fh, "%d", &max_bits)!=1)
+ max_bits = -1;
+ fclose(poolsize_fh);
+ osrel_fh = fopen(params->os_rel, "rb");
+ if (osrel_fh) {
+ if (fscanf(osrel_fh,"%u.%u", &major, &minor)<2)
+ major = minor = 0;
+ fclose(osrel_fh);
+ if (major==2 && minor==4) max_bits *= 8;
+ }
+ }
+ else max_bits = -1;
+ if (max_bits < 1)
+ error_exit("Couldn't get poolsize");
+ return max_bits;
+}
+/**
+ * Run as a daemon writing to random device entropy pool
+ */
+static void run_daemon( /* RETURN: nothing */
+ H_PTR h, /* IN: app instance */
+ const volatile char *path,
+ char *const argv[])
+{
+ int random_fd = -1;
+#ifndef NO_COMMAND_MODE
+ int conn_fd = -1;
+#endif
+ struct rand_pool_info *output;
+ struct stat stat_buf;
+
+ if (0 != params->run_level) {
+ anchor_info(h);
+ return;
+ }
+ if (params->foreground==0) {
+ daemonize();
+ havege_reparent(handle);
+ }
+ else printf ("%s starting up\n", params->daemon);
+ if (0 != havege_run(h))
+ error_exit("Couldn't initialize HAVEGE rng %d", h->error);
+ if (0 != (params->verbose & H_DEBUG_INFO))
+ anchor_info(h);
+ if (params->low_water>0)
+ set_watermark(params->low_water);
+ if ( lstat(params->random_device, &stat_buf) != 0 )
+ error_exit("lstat has failed for the random device \"%s\": %s", params->random_device, strerror(errno));
+ if ( S_ISLNK(stat_buf.st_mode) )
+ error_exit("random device \"%s\" is a link. This is not supported for the security reasons.", params->random_device);
+ random_fd = open(params->random_device, O_RDWR);
+ if (random_fd == -1)
+ error_exit("Couldn't open random device: %s", strerror(errno));
+
+ output = (struct rand_pool_info *) h->io_buf;
+
+#if NUMBER_CORES>1
+ pthread_sigmask(SIG_BLOCK, &mask, &omask);
+#else
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+#endif
+ for(;;) {
+ int current,nbytes,r,max=0;
+ fd_set write_fd;
+#ifndef NO_COMMAND_MODE
+ fd_set read_fd;
+#endif
+
+ if (params->exit_code > 128)
+ error_exit("Stopping due to signal %d\n", params->exit_code - 128);
+
+ FD_ZERO(&write_fd);
+#ifndef NO_COMMAND_MODE
+ if (socket_fd >= 0) {
+ FD_ZERO(&read_fd);
+ }
+#endif
+ FD_SET(random_fd, &write_fd);
+ if (random_fd > max)
+ max = random_fd;
+#ifndef NO_COMMAND_MODE
+ if (socket_fd >= 0) {
+ FD_SET(socket_fd, &read_fd);
+ if (socket_fd > max)
+ max = socket_fd;
+ if (conn_fd >= 0) {
+ FD_SET(conn_fd, &read_fd);
+ if (conn_fd > max)
+ max = conn_fd;
+ }
+ }
+#endif
+ for(;;) {
+ struct timespec two = {2, 0};
+ int rc;
+#ifndef NO_COMMAND_MODE
+ if (socket_fd >= 0) {
+ rc = pselect(max+1, &read_fd, &write_fd, NULL, &two, &omask);
+ } else {
+ rc = pselect(max+1, NULL, &write_fd, NULL, &two, &omask);
+ }
+#else
+ rc = pselect(max+1, NULL, &write_fd, NULL, &two, &omask);
+#endif
+ if (rc >= 0) break;
+ if (params->exit_code > 128)
+ break;
+ if (errno != EINTR)
+ error_exit("Select error: %s", strerror(errno));
+ }
+ if (params->exit_code > 128)
+ continue;
+
+#ifndef NO_COMMAND_MODE
+ if ( socket_fd >= 0 && FD_ISSET(socket_fd, &read_fd) && conn_fd < 0) {
+# ifdef HAVE_ACCEPT4
+ conn_fd = accept4(socket_fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
+ if (conn_fd < 0 && (errno == ENOSYS || errno == ENOTSUP)) {
+# endif
+ conn_fd = accept(socket_fd, NULL, NULL);
+ if (conn_fd >= 0) {
+ fcntl(conn_fd, F_SETFL, O_NONBLOCK);
+ fcntl(conn_fd, F_SETFD, FD_CLOEXEC);
+ }
+# ifdef HAVE_ACCEPT4
+ }
+# endif
+ if (conn_fd >= 0)
+ continue;
+ }
+
+ if (conn_fd >= 0 && FD_ISSET(conn_fd, &read_fd))
+ conn_fd = socket_handler(conn_fd, path, argv, params);
+#endif
+ if (!FD_ISSET(random_fd, &write_fd))
+ continue;
+
+ if (ioctl(random_fd, RNDGETENTCNT, &current) == -1)
+ error_exit("Couldn't query entropy-level from kernel");
+ /* get number of bytes needed to fill pool */
+ nbytes = (poolSize - current)/8;
+ if(nbytes<1) continue;
+ /* get that many random bytes */
+ r = (nbytes+sizeof(H_UINT)-1)/sizeof(H_UINT);
+ if (havege_rng(h, (H_UINT *)output->buf, r)<1)
+ error_exit("RNG failed! %d", h->error);
+ output->buf_size = nbytes;
+ /* entropy is 8 bits per byte */
+ output->entropy_count = nbytes * 8;
+ if (ioctl(random_fd, RNDADDENTROPY, output) == -1)
+ error_exit("RNDADDENTROPY failed!");
+ }
+}
+/**
+ * Set random write threshold
+ */
+static void set_watermark( /* RETURN: nothing */
+ int level) /* IN: threshold */
+{
+ FILE *wm_fh;
+
+ if ( (H_UINT) level > (poolSize - 32))
+ level = poolSize - 32;
+ wm_fh = fopen(params->watermark, "w");
+ if (wm_fh) {
+ fprintf(wm_fh, "%d\n", level);
+ fclose(wm_fh);
+ }
+ else if (errno == EACCES)
+ fprintf(stderr, "No access to %s, can't set watermark (maybe running in a container?)\n",
+ params->watermark);
+ else error_exit("Fail:set_watermark()!");
+}
+#endif
+/**
+ * Display handle information
+ */
+static void anchor_info(H_PTR h)
+{
+ char buf[120];
+ H_SD_TOPIC topics[4] = {H_SD_TOPIC_BUILD, H_SD_TOPIC_TUNE, H_SD_TOPIC_TEST, H_SD_TOPIC_SUM};
+ int i;
+
+ for(i=0;i<4;i++)
+ if (havege_status_dump(h, topics[i], buf, sizeof(buf))>0)
+ print_msg("%s\n", buf);
+}
+/**
+ * Bail....
+ */
+void error_exit( /* RETURN: nothing */
+ const char *format, /* IN: msg format */
+ ...) /* IN: varadic args */
+{
+ char buffer[4096];
+
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+#ifndef NO_DAEMON
+ if (params->detached!=0) {
+ unlink(params->pid_file);
+ syslog(LOG_INFO, "%s: %s", params->daemon, buffer);
+ }
+ else
+#endif
+ {
+ fprintf(stderr, "%s: %s\n", params->daemon, buffer);
+ if (0 !=(params->setup & RUN_AS_APP) && 0 != handle) {
+ if (havege_status_dump(handle, H_SD_TOPIC_TEST, buffer, sizeof(buffer))>0)
+ fprintf(stderr, "%s\n", buffer);
+ if (havege_status_dump(handle, H_SD_TOPIC_SUM, buffer, sizeof(buffer))>0)
+ fprintf(stderr, "%s\n", buffer);
+ }
+ }
+ havege_destroy(handle);
+ exit(params->exit_code);
+}
+/**
+ * Implement fixed point shorthand for run sizes
+ */
+static int get_runsize( /* RETURN: the size */
+ H_UINT *bufct, /* OUT: nbr app buffers */
+ H_UINT *bufrem, /* OUT: residue */
+ char *bp) /* IN: the specification */
+{
+ char *suffix;
+ double f;
+ int p2 = 0;
+ int p10 = APP_BUFF_SIZE * sizeof(H_UINT);
+ long long ct;
+
+
+ f = strtod(bp, &suffix);
+ if (f < 0 || strlen(suffix)>1)
+ return 1;
+ switch(*suffix) {
+ case 't': case 'T':
+ p2 += 1;
+ /* fallthrough */
+ case 'g': case 'G':
+ p2 += 1;
+ /* fallthrough */
+ case 'm': case 'M':
+ p2 += 1;
+ /* fallthrough */
+ case 'k': case 'K':
+ p2 += 1;
+ /* fallthrough */
+ case 0:
+ break;
+ default:
+ return 2;
+ }
+ while(p2-- > 0)
+ f *= 1024;
+ ct = f;
+ if (f != 0 && ct==0)
+ return 3;
+ if ((double) (ct+1) < f)
+ return 3;
+ *bufrem = (H_UINT)(ct%p10);
+ *bufct = (H_UINT)(ct/p10);
+ if (*bufct == (ct/p10))
+ return 0;
+ /* hack to allow 16t */
+ ct -= 1;
+ *bufrem = (H_UINT)(ct%p10);
+ *bufct = (H_UINT)(ct/p10);
+ return (*bufct == (ct/p10))? 0 : 4;
+}
+#ifdef RAW_IN_ENABLE
+/**
+ * The injection diagnostic
+ */
+static int injectFile( /* RETURN: not used */
+ volatile H_UINT *pData, /* OUT: data buffer */
+ H_UINT szData) /* IN: H_UINT needed */
+{
+ int r;
+ if ((r=fread((void *)pData, sizeof(H_UINT), szData, fd_in)) != szData)
+ error_exit("Cannot read data in file: %d!=%d", r, szData);
+ return 0;
+}
+#endif
+/**
+ * Pretty print the collection size
+ */
+static char *ppSize( /* RETURN: the formatted size */
+ char *buffer, /* IN: work space */
+ double sz) /* IN: the size */
+{
+ char units[] = {'T', 'G', 'M', 'K', 0};
+ double factor = 1024.0 * 1024.0 * 1024.0 * 1024.0;
+ int i;
+
+ for (i=0;0 != units[i];i++) {
+ if (sz >= factor)
+ break;
+ factor /= 1024.0;
+ }
+ snprintf(buffer, 32, "%.4g %c byte", sz / factor, units[i]);
+ return buffer;
+}
+/**
+ * Execution notices - to stderr or syslog
+ */
+void print_msg( /* RETURN: nothing */
+ const char *format, /* IN: format string */
+ ...) /* IN: args */
+{
+ char buffer[128];
+
+ va_list ap;
+ va_start(ap, format);
+ snprintf(buffer, sizeof(buffer), "%s: %s", params->daemon, format);
+#ifndef NO_DAEMON
+ if (params->detached != 0)
+ vsyslog(LOG_INFO, buffer, ap);
+ else
+#endif
+ vfprintf(stderr, buffer, ap);
+ va_end(ap);
+}
+/**
+* Run as application writing to a file
+*/
+static void run_app( /* RETURN: nothing */
+ H_PTR h, /* IN: app instance */
+ H_UINT bufct, /* IN: # buffers to fill */
+ H_UINT bufres) /* IN: # bytes extra */
+{
+ H_UINT *buffer;
+ FILE *fout = NULL;
+ H_UINT ct=0;
+ int limits = bufct;
+
+ if (0 != havege_run(h))
+ error_exit("Couldn't initialize HAVEGE rng %d", h->error);
+ if (0 != (params->setup & USE_STDOUT)) {
+ params->sample_out = "stdout";
+ fout = stdout;
+ }
+ else if (!(fout = fopen (params->sample_out, "wb")))
+ error_exit("Cannot open file <%s> for writing.\n", params->sample_out);
+ limits = bufct!=0? 1 : bufres != 0;
+ buffer = (H_UINT *)h->io_buf;
+#ifdef RAW_IN_ENABLE
+ {
+ char *format, *in="",*out,*sz,*src="";
+
+ if (params->run_level==DIAG_RUN_INJECT)
+ in = "tics";
+ else if (params->run_level==DIAG_RUN_TEST)
+ in = "data";
+ if (*in!=0) {
+ src =(fd_in==stdin)? "stdin" : params->sample_in;
+ format = "Inject %s from %s, writing %s bytes to %s\n";
+ }
+ else format = "Writing %s%s%s bytes to %s\n";
+ if (limits)
+ sz = ppSize((char *)buffer, (1.0 * bufct) * APP_BUFF_SIZE * sizeof(H_UINT) + bufres);
+ else sz = "unlimited";
+ out = (fout==stdout)? "stdout" : params->sample_out;
+ fprintf(stderr, format, in, src, sz, out);
+ }
+#else
+ if (limits)
+ fprintf(stderr, "Writing %s output to %s\n",
+ ppSize((char *)buffer, (1.0 * bufct) * APP_BUFF_SIZE * sizeof(H_UINT) + bufres), params->sample_out);
+ else fprintf(stderr, "Writing unlimited bytes to stdout\n");
+#endif
+ while(!limits || ct++ < bufct) {
+ if (havege_rng(h, buffer, APP_BUFF_SIZE)<1)
+ error_exit("RNG failed %d!", h->error);
+ if (fwrite (buffer, 1, APP_BUFF_SIZE * sizeof(H_UINT), fout) == 0)
+ error_exit("Cannot write data in file: %s", strerror(errno));
+ }
+ ct = (bufres + sizeof(H_UINT) - 1)/sizeof(H_UINT);
+ if (ct) {
+ if (havege_rng(h, buffer, ct)<1)
+ error_exit("RNG failed %d!", h->error);
+ if (fwrite (buffer, 1, bufres, fout) == 0)
+ error_exit("Cannot write data in file: %s", strerror(errno));
+ }
+ fclose(fout);
+ if (0 != (params->verbose & H_DEBUG_INFO))
+ anchor_info(h);
+}
+/**
+ * Show collection info.
+ */
+static void show_meterInfo( /* RETURN: nothing */
+ H_UINT id, /* IN: identifier */
+ H_UINT event) /* IN: start/stop */
+{
+ struct timeval tm;
+ /* N.B. if multiple thread, each child gets its own copy of this */
+ static H_METER status;
+
+ gettimeofday(&tm, NULL);
+ if (event == 0)
+ status.estart = ((double)tm.tv_sec*1000.0 + (double)tm.tv_usec/1000.0);
+ else {
+ status.etime = ((double)tm.tv_sec*1000.0 + (double)tm.tv_usec/1000.0);
+ if ((status.etime -= status.estart)<0.0)
+ status.etime=0.0;
+ status.n_fill += 1;
+ print_msg("%d fill %g ms\n", id, status.etime);
+ }
+}
+/**
+ * Signal handler
+ */
+static void tidy_exit( /* OUT: nothing */
+ int signum) /* IN: signal number */
+{
+ params->exit_code = 128 + signum;
+}
+
+/**
+ * send usage display to stderr
+ */
+static void usage( /* OUT: nothing */
+ int loc, /* IN: debugging aid */
+ int nopts, /* IN: number of options */
+ struct option *long_options, /* IN: long options */
+ const char **cmds) /* IN: associated text */
+{
+ int i, j;
+
+ (void)loc;
+ fprintf(stderr, "\nUsage: %s [options]\n\n", params->daemon);
+#ifndef NO_DAEMON
+ fprintf(stderr, "Collect entropy and feed into random pool or write to file.\n");
+#else
+ fprintf(stderr, "Collect entropy and write to file.\n");
+#endif
+ fprintf(stderr, " Options:\n");
+ for(i=j=0;long_options[i].val != 0;i++,j+=4) {
+ while(cmds[j][0] != long_options[i].val && (j+4) < (nopts * 4))
+ j += 4;
+ fprintf(stderr," --%-10s, -%c %s %s\n",
+ long_options[i].name, long_options[i].val,
+ long_options[i].has_arg? "[]":" ",cmds[j+3]);
+ }
+ fprintf(stderr, "\n");
+ exit(1);
+}
diff --git a/src/haveged.h b/src/haveged.h
new file mode 100644
index 0000000..6f38c17
--- /dev/null
+++ b/src/haveged.h
@@ -0,0 +1,100 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HAVEGED_H
+#define HAVEGED_H
+
+#include "havege.h"
+/**
+ * Settings - default values declared in haveged.c
+ */
+struct pparams {
+ char *daemon; /* Daemon name - default is "haveged" */
+ H_UINT exit_code; /* Exit code */
+ H_UINT setup; /* setup options */
+ H_UINT ncores; /* number of cores to use */
+ H_UINT buffersz; /* size of collection buffer (kb) */
+ H_UINT detached; /* non-zero if daemonized */
+ H_UINT foreground; /* non-zero if running in foreground */
+ H_UINT run_level; /* type of run 0=daemon,1=setup,2=pip,sample kb */
+ H_UINT d_cache; /* size of data cache (kb) */
+ H_UINT i_cache; /* size of instruction cache (kb) */
+ H_UINT low_water; /* write threshold to set - 0 for none */
+ char *tests_config; /* online test configuration */
+ char *os_rel; /* path to operating system release */
+ char *pid_file; /* name of pid file */
+ char *poolsize; /* path to poolsize */
+ char *random_device; /* path to random device */
+ char *sample_in; /* input path for injection diagnostic */
+ char *sample_out; /* path to sample file */
+ H_UINT verbose; /* Output level for log or stdout */
+ char *version; /* Our version */
+ char *watermark; /* path to write_wakeup_threshold */
+ char *command; /* command which will be send/received */
+ };
+/**
+ * Buffer size used when not running as daemon
+ */
+#define APP_BUFF_SIZE 1024
+#define INPUT_DEFAULT "data"
+#define OUTPUT_DEFAULT "sample"
+#define PID_DEFAULT "/var/run/haveged.pid"
+/**
+ * Setup options (for app)
+ */
+#define RUN_AS_APP 0x001
+#define RANGE_SPEC 0x002
+#define USE_STDOUT 0x004
+#define CAPTURE 0x008
+#define INJECT 0x010
+#define RUN_IN_FG 0x020
+#define SET_LWM 0x040
+#define MULTI_CORE 0x080
+#define CMD_MODE 0x100
+/**
+ * Default tests settings
+ */
+#define TESTS_DEFAULT_APP "ta8b" /* startup tests */
+#define TESTS_DEFAULT_RUN "ta8bcb" /* startup + continuous B */
+/**
+ * Run levels for diagnostic build
+ */
+#define DIAG_RUN_CAPTURE 2 /* output clock ticks */
+#define DIAG_RUN_INJECT 4 /* inject clock ticks */
+#define DIAG_RUN_TEST 8 /* inject test data */
+/**
+ * Status/monitoring information
+ */
+typedef struct {
+ H_UINT n_fill; /* number times filled */
+ double etime; /* milliseconds for last collection */
+ double estart; /* start time for calculation */
+} H_METER;
+
+/**
+ * Bail....
+ */
+void error_exit(const char *, ...);
+
+/**
+ * Execution notices - to stderr or syslog
+ */
+void print_msg(const char *, ...);
+
+#endif
diff --git a/src/havegetest.c b/src/havegetest.c
new file mode 100644
index 0000000..74c72b0
--- /dev/null
+++ b/src/havegetest.c
@@ -0,0 +1,1030 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2012-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * This compile unit implements online tests for haveged through the public functions tests*.
+ * Online tests are run directly against the contents of the collection buffer immediately after
+ * a buffer fill. Because collection buffer size does not have any direct relationship with
+ * the data requirements of the individual tests, all tests implement a state machine to
+ * handle segmented input.
+ *
+ * Note code directly related to the havege interface has been moved to a conditional
+ * in that unit for easier maintainability.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "havegetest.h"
+
+#ifdef ONLINE_TESTS_ENABLE
+/**
+ * Final value for aisSeq() when no transition found. Originally, Initially this used
+ * INFINITY from <math.h> but definition is undefined some gcc versions - foo!
+ */
+#define NO_TRANSITION 999999
+/**
+ * This structure is used only to pack the test structures into a single memory allocation.
+ * This is necessary because some architectures have stringent alignment requirements that
+ * cannot be met unless (compiler generated) padding is included. On mips in particular
+ * double must be dword aligned or bus errors result.
+ */
+typedef struct {
+ onlineTests olt;
+ procA pa;
+ procB pb;
+} testsMemory;
+/**
+ * The tests and supporting methods
+ */
+static H_UINT aisProcedureA(H_COLLECT *h_ctxt, procShared *tps,
+ procA *context, H_UINT *buffer, H_UINT sz, H_UINT offs, H_UINT prod);
+static H_UINT aisProcedureB(H_COLLECT *h_ctxt, procShared *tps,
+ procB *context, H_UINT *buffer, H_UINT sz, H_UINT offs, H_UINT prod);
+static H_UINT aisSeq(procB *p, H_UINT offs, H_UINT id);
+static H_UINT aisTest(H_COLLECT * h_ctxt, H_UINT prod, H_UINT *buffer, H_UINT sz);
+static H_UINT copyBits(procA *p, H_UINT ct,H_UINT sz);
+static H_UINT fips140(procShared *tps, procA *p, H_UINT offs, H_UINT id);
+static H_UINT test0(procA *p, H_UINT offs, H_UINT id);
+static int test0cmp(const void *aa, const void *bb);
+static H_UINT test5(procA *p, H_UINT offs, H_UINT id);
+static H_UINT test5XOR(H_UINT8 *src, H_UINT shift);
+static H_UINT test6a(procB *p, H_UINT offs, H_UINT id);
+static H_UINT test8(procShared *tps, procB *p, H_UINT offs, H_UINT id);
+static int testsDiscard(H_COLLECT *rdr);
+static void testsMute(H_COLLECT * h_ctxt, H_UINT action, H_UINT prod, H_UINT state, H_UINT ct);
+static int testsRun(H_COLLECT *rdr, H_UINT prod);
+
+/**
+ * The following suite of macros encapsulate the major bit operations of the test suite.
+ * The intention is to write simple rather than clever code and let the optimizer strut
+ * it's sutff. Note bit index starts with MSB for direct comparison with the test suit'e
+ * Java reference implementation.
+ */
+#define BITSTREAM_BIT() ((*bitstream_src)&bitstream_in)==0? 0 : 1
+#define BITSTREAM_NEXT() {if (bitstream_in==1) {\
+ bitstream_src+=1;\
+ bitstream_in=0x80;\
+ }\
+ else bitstream_in>>=1;}
+#define BITSTREAM_OPEN(a,b) H_UINT8 *bitstream_src=(H_UINT8 *)(a);\
+ H_UINT bitstream_in=0x80>>((b)%8);\
+ bitstream_src+=(b)/8
+/**
+ * Setup shared resources for online tests by sorting the test options into "tot"
+ * and production groupings and allocating any resources used by the tests.
+ * Caller is responsible for initializing the procShared structure with the
+ * report, testsUsed, totTests[], runTests[], totText, and prodText fields.
+ */
+int havege_test( /* RETURN: nz on failure */
+ procShared *tps, /* IN-OUT: test anchor */
+ H_PARAMS *params) /* IN: app parameters */
+{
+ H_UINT i;
+
+ tps->discard = testsDiscard;
+ if (0==tps->report)
+ tps->report = testsMute;
+ tps->run = testsRun;
+ tps->options = params->options;
+
+ if (0!=(tps->testsUsed & A_RUN)) {
+ H_UINT low[6] = {FIPS_RUNS_LOW};
+ H_UINT high[6] = {FIPS_RUNS_HIGH};
+
+ tps->procReps = 1 + (5 * AIS_A_REPS);
+ for (i=0;i<6;i++) {
+ tps->fips_low[i] = low[i];
+ tps->fips_high[i] = high[i];
+ }
+ }
+ if (0!=(tps->testsUsed & B_RUN)) {
+ tps->G = (double *) malloc((Q+K+1)*sizeof(double));
+ if (0 == tps->G)
+ return 1;
+ tps->G[1] = 0.0;
+ for(i=1; i<=(K+Q-1); i++)
+ tps->G[i+1]=tps->G[i]+1.0/i;
+ for(i=1; i<=(K+Q); i++)
+ tps->G[i] /= LN2;
+ }
+ return 0;
+}
+/**
+ * Check if the current buffer should be released if continuous testing is
+ * being performed. The buffer must be discarded if it contains an
+ * uncompleted retry or an uncompleted procedure with a failed test
+ * or a failed procedure.
+ */
+static int testsDiscard( /* RETURN: non-zero to discard */
+ H_COLLECT * h_ctxt) /* IN-OUT: collector context */
+{
+ onlineTests *context = (onlineTests *) h_ctxt->havege_tests;
+ procShared *tps = TESTS_SHARED(h_ctxt);
+ procInst *p;
+ H_UINT i;
+
+ if (0==tps->testsUsed)
+ return 0;
+ if (context->result!=0)
+ return -1;
+ p = tps->runTests + context->runIdx;
+ switch(p->action) {
+ case A_RUN:
+ if (0 != context->pA->procRetry)
+ return 1;
+ for (i = 0;i<context->pA->testRun;i++)
+ if (0 !=(context->pA->results[i].testResult & 1))
+ return 1;
+ break;
+ case B_RUN:
+ if (0 != context->pB->procRetry)
+ return 1;
+ for (i=0;i<context->pB->testNbr;i++)
+ if (0!=(context->pB->results[i].testResult & 0xff))
+ return 1;
+ break;
+ }
+ return 0;
+}
+/**
+ * Place holder for when report is not configured
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+static void testsMute(
+ H_COLLECT * h_ctxt, /* IN-OUT: collector context */
+ H_UINT action, /* IN: A_RUN or B_RUN */
+ H_UINT prod, /* IN: 0==tot, else continuous */
+ H_UINT state, /* IN: state variable */
+ H_UINT ct) /* IN: bytes consumed */
+{
+ ;
+}
+#pragma GCC diagnostic pop
+/**
+ * The public wrapper that runs the tests. On the first call, the necessary machinery is built.
+ * The calls to aisTest() actually run the tests. The test shared structure is read only in this
+ * case, since testsRun could be called in a multi-threaded environment where an onlineTests
+ * structure is associated with each collection thread.
+ */
+static int testsRun( /* RETURN: nz if input needed */
+ H_COLLECT * h_ctxt, /* IN-OUT: collector context */
+ H_UINT prod) /* IN: nz if production else tot */
+{
+ procShared *tps = TESTS_SHARED(h_ctxt);
+ onlineTests *context;
+ testsMemory *mem;
+ procB *pb;
+
+ if (0 ==(tps->testsUsed))
+ return 0;
+ if (0 == h_ctxt->havege_tests) {
+ H_UINT sz = sizeof(testsMemory);
+
+ if (0==(tps->testsUsed & A_RUN))
+ sz -= sizeof(procA);
+ if (0==(tps->testsUsed & B_RUN))
+ sz -= sizeof(procB);
+ mem = (testsMemory *) malloc(sz);
+ if (NULL==mem) {
+ h_ctxt->havege_err = H_NOTESTMEM;
+ return 1;
+ }
+ context = (onlineTests *) mem;
+ memset(context, 0, sizeof(onlineTests));
+ if (0!=(tps->testsUsed & A_RUN)) {
+ context->pA = &mem->pa;
+ context->pA->procState = TEST_INIT;
+ pb = &mem->pb;
+ }
+ else pb = (procB *)((void *) &mem->pa);
+ if (0!=(tps->testsUsed & B_RUN)) {
+ context->pB = pb;
+ context->pB->procState = TEST_INIT;
+ }
+ h_ctxt->havege_tests = context;
+ if (0 != (h_ctxt->havege_raw & H_DEBUG_TEST_IN))
+ return 0;
+ }
+ return aisTest(h_ctxt, prod, (H_UINT *)h_ctxt->havege_bigarray, h_ctxt->havege_szFill);
+}
+/**
+ * AIS-31 test procedure A. The test is initiated by setting procState to TEST_INIT and
+ * the test is performed by calling the procedure adding input until completion is indicated
+ * by a proc state of TEST_DONE. The first test requires 3145728 bits (393,216 bytes) and
+ * the remaining 5 tests are repeated on sucessive 2500 byte samples for 257 times.
+ *
+ * Exit states TEST_DONE, TEST_IGNORE, TEST_INPUT, TEST_RETRY
+ *
+ * An ideal RNG will pass this test with a probablilty of 0.9987. If there is a single failed
+ * test, the test will be repeated. An ideal RNG should almost never fail the retry. The goal
+ * of this procedure is to verify RNG output is statisically inconspicuous.
+ */
+static H_UINT aisProcedureA( /* RETURN: bits used */
+ H_COLLECT *h_ctxt, /* IN-OUT: collection instance */
+ procShared *tps, /* IN-OUT: shared data */
+ procA *p, /* IN: the context */
+ H_UINT *buffer, /* IN: the input */
+ H_UINT sz, /* IN: the input range */
+ H_UINT ct, /* IN: initial bit offset */
+ H_UINT prod) /* IN: production if nz */
+{
+ onlineTests *context = TESTS_CONTEXT(h_ctxt);
+ H_UINT i, r;
+
+ switch(p->procState) {
+ case TEST_INIT:
+ p->bytesUsed = 0;
+ p->procRetry = 0;
+ /* fallthrough */
+ case TEST_RETRY:
+ p->procState = TEST_INPUT;
+ p->testState = TEST_INIT;
+ p->testId = p->testRun = 0;
+ /* fallthrough */
+ case TEST_INPUT:
+ p->data = (H_UINT8 *)buffer;
+ p->range = sz * sizeof(H_UINT) <<3;
+ while(p->testRun < tps->procReps) {
+ p->testId = p->testRun<6? p->testRun : (1+(p->testRun-6) % 5);
+ switch(p->testId) {
+ case 0:
+ ct = test0(p, ct, p->testRun);
+ break;
+ case 1: case 2: case 3: case 4:
+ ct = fips140(tps, p, ct, p->testRun);
+ break;
+ case 5:
+ ct = test5(p, ct, p->testRun);
+ break;
+ }
+ context->szCarry = ct;
+ if (p->testState == TEST_DONE)
+ p->testState = TEST_INPUT;
+ else if (p->testState == TEST_INPUT)
+ return 0;
+ }
+ /* fallthrough */
+ case TEST_EVAL:
+ p->procState = TEST_DONE;
+ for (r = i = 0;i<p->testRun;i++)
+ r += p->results[i].testResult & 1;
+ if (0!=r) {
+ tps->meters[prod? H_OLT_PROD_A_F : H_OLT_TOT_A_F] += 1;
+ if (1==r && 0==p->procRetry) {
+ p->procRetry = 1;
+ p->procState = TEST_RETRY;
+ }
+ else if (0!=(p->options & A_WARN))
+ p->procState = TEST_IGNORE;
+ else {
+ context->result = A_RUN;
+ h_ctxt->havege_err = prod? H_NOTESTRUN : H_NOTESTTOT;
+ }
+ break;
+ }
+ else tps->meters[prod? H_OLT_PROD_A_P : H_OLT_TOT_A_P] += 1;
+ if (0!=(tps->options & (H_DEBUG_OLT|H_DEBUG_OLT))|| TEST_DONE != p->procState)
+ tps->report(h_ctxt, A_RUN, prod, p->procState, p->bytesUsed);
+ break;
+ }
+ return p->bytesUsed<<3;
+}
+/**
+ * AIS-31 test procedure B. The test is initiated by setting procState to TEST_INIT and
+ * the test is performed by calling the procedure adding input until completion is indicated
+ * by a proc state of TEST_DONE. Unlike procedure A, the number of input bits is not fixed
+ * but depends on the input.
+ *
+ * Exit states TEST_DONE, TEST_IGNORE, TEST_INPUT, TEST_RETRY
+ *
+ * The probability that an ideal RNG will pass this test is 0.9998. If a single test fails,
+ * the test is repeated. An ideal RNG should almost never fail the retry. The goal of this
+ * procedure is to ensure the entropy of the output is sufficiently large.
+ */
+static H_UINT aisProcedureB( /* RETURN: bits used */
+ H_COLLECT *h_ctxt, /* IN-OUT: collection instance */
+ procShared *tps, /* IN-OUT: shared data */
+ procB *p, /* IN: the context */
+ H_UINT *buffer, /* IN: the input */
+ H_UINT sz, /* IN: the input range */
+ H_UINT ct, /* IN: initial bit offset */
+ H_UINT prod) /* IN: production if nz */
+{
+ onlineTests *context = TESTS_CONTEXT(h_ctxt);
+ H_UINT i, r;
+
+ switch(p->procState) {
+ case TEST_INIT:
+ p->bitsUsed = 0;
+ p->procRetry = 0;
+ /* fallthrough */
+ case TEST_RETRY:
+ p->testId = p->testNbr = 0;
+ p->procState = TEST_INPUT;
+ p->testState = TEST_INIT;
+ /* fallthrough */
+ case TEST_INPUT:
+ p->noise = buffer;
+ p->range = sz * BITS_PER_H_UINT;
+ i = p->testId;
+ while(p->testState != TEST_DONE && i < 5) {
+ p->seq = 1<<i;
+ switch(i) {
+ case 0: ct = test6a(p, ct, i); break;
+ case 4: ct = test8(tps,p,ct,i); break;
+ default: ct = aisSeq(p,ct,i); break;
+ }
+ if (p->testState == TEST_INPUT)
+ break;
+ p->testId = ++i;
+ p->testState = TEST_INIT;
+ }
+ context->szCarry = ct;
+ if (p->testState == TEST_INPUT)
+ return 0;
+ /* fallthrough */
+ case TEST_EVAL:
+ p->procState = TEST_DONE;
+ for (i=r=0;i<p->testNbr;i++)
+ r += p->results[i].testResult & 1;
+ if (0!=r) {
+ tps->meters[prod? H_OLT_PROD_B_F : H_OLT_TOT_B_F] += 1;
+ if (1==r && 0==p->procRetry) {
+ p->procRetry = 1;
+ p->procState = TEST_RETRY;
+ }
+ else if (0!=(p->options & B_WARN))
+ p->procState = TEST_IGNORE;
+ else {
+ context->result = B_RUN;
+ h_ctxt->havege_err = prod? H_NOTESTRUN : H_NOTESTTOT;
+ }
+ }
+ else tps->meters[prod? H_OLT_PROD_B_P : H_OLT_TOT_B_P] += 1;
+ if (0!=(tps->options & H_DEBUG_OLT)|| TEST_DONE != p->procState)
+ tps->report(h_ctxt, B_RUN, prod, p->procState, p->bitsUsed/8);
+ break;
+ }
+ return p->bitsUsed;
+}
+/**
+ * Driver for disjoint sequence tests - steps 2,3,4 of AIS-31 procedure B (aka test6b, test7a, and test7b).
+ * Input tid is the width of the transition to be analyzed: tid=1 { 0x, 1x }, tid=2 {00x, 01x, 10x, 11x},
+ * tid=3 {000x, 001x, 010x, 011x, 100x, 101x, 110x, 111x}. The seq menber of procB gives # categories.
+ * For a tuple of width n, transition probabilities are calculated for log2(n) transitions for the first
+ * 100000 sequences. The deadman counter prevents total runaways with pathalogical input by counting
+ * interations that fail to update any counter. If the deadman value exceeds the limit, evaluation of
+ * the result forced. The probability of a forced evaluation is 10e-15.
+ *
+ * The macros below use fields in the procB structure to save/restore context when the input is
+ * segmented.
+ */
+#define RESTORE(a,b,c) a=p->bridge;b=p->lastpos[0];c=p->lastpos[1]
+#define SAVE(a,b,c) p->bridge=a;p->lastpos[0]=b;p->lastpos[1]=c
+
+static H_UINT aisSeq( /* RETURN: last bit index */
+ procB *p, /* IN-OUT: the context */
+ H_UINT offs, /* IN: starting bit offset */
+ H_UINT tid) /* IN: test id == #bits */
+{
+ static const H_UINT seq_dead[5] = {0, 50, 120, 258, 0}; /* dead man limit */
+ static const H_UINT seq_mask[5] = {0, 3, 15, 255, 0}; /* full mask */
+ H_UINT i=0, c, deadman, r, s, j, hilf;
+
+ switch(p->testState) {
+ case TEST_INIT:
+ for(j=0;j<p->seq;j++)
+ p->counter[j] = p->einsen[j] = 0;
+ p->full = 0;
+ p->testState = TEST_INPUT;
+ SAVE(0,0,0);
+ /* fallthrough */
+ case TEST_INPUT:
+ RESTORE(j, hilf, deadman);
+ offs %= p->range;
+ r = p->range - offs;
+ s = r % (tid+1);
+ r -= s;
+ {
+ BITSTREAM_OPEN(p->noise,offs);
+ while(i<r) {
+ for(;j<tid;i++,j++) {
+ hilf += hilf+(BITSTREAM_BIT());BITSTREAM_NEXT();
+ }
+ c = BITSTREAM_BIT();BITSTREAM_NEXT();
+ i += 1;
+ if (0!=(p->full & (1<<hilf))) {
+ if ((deadman+=1)> seq_dead[tid]) {
+ p->testState = TEST_DONE;
+ break;
+ }
+ }
+ else {
+ deadman = 0;
+ p->einsen[hilf] += c;
+ if ((p->counter[hilf]+=1)==AIS_LENGTH) {
+ p->full |= (1<<hilf);
+ if (p->full == seq_mask[tid]) {
+ p->testState = TEST_EVAL;
+ break;
+ }
+ }
+ }
+ j = hilf = 0;
+ }
+ if (p->testState==TEST_INPUT) {
+ for(j=hilf=0;j<s;j++,i++) {
+ hilf += hilf+(BITSTREAM_BIT());BITSTREAM_NEXT();
+ }
+ SAVE(j,hilf,deadman);
+ }
+ }
+ p->bitsUsed += i;
+ if (p->testState == TEST_INPUT)
+ break;
+ /* fallthrough */
+ case TEST_EVAL:
+ if (tid==1) {
+ double q[2];
+
+ if (p->testState == TEST_EVAL) {
+ for(j=0;j<2;j++)
+ q[j] = (double)(p->einsen[j]) / (double) AIS_LENGTH;
+ p->results[p->testNbr].finalValue = q[0] - q[1];
+ }
+ else p->results[p->testNbr].finalValue = NO_TRANSITION;
+ hilf = tid << 8;
+ if (p->results[p->testNbr].finalValue <= -0.02 || p->results[p->testNbr].finalValue >= 0.02)
+ hilf |= 1;
+ p->results[p->testNbr++].testResult = hilf;
+ }
+ else {
+ /**
+ * The spec is very confusing but the reference implementation is correct. The test
+ * operates on observed transions, i.e. the difference between pairs of successive
+ * einsen and nullen (AIS_LENGTH - einsen)
+ */
+ for(j=0; j<p->seq; j+=2) {
+ if (p->testState == TEST_EVAL) {
+ double qn = (double)((int)p->einsen[j] - (int)p->einsen[j+1]);
+ double qd = (double)(p->einsen[j] + p->einsen[j+1]);
+ double pd = AIS_LENGTH * 2.0 - qd;
+ p->results[p->testNbr].finalValue = ((qn * qn) / pd) + ((qn * qn) / qd);
+ }
+ else p->results[p->testNbr].finalValue = NO_TRANSITION;
+ hilf = tid << 8;
+ if (p->results[p->testNbr].finalValue > 15.13)
+ hilf |= 1;
+ p->results[p->testNbr++].testResult = hilf;
+ }
+ }
+ p->testState = TEST_DONE;
+ break;
+ }
+ return i+offs;
+}
+/**
+ * Run the configured test procedures. This function cycles the procedure calls
+ * setup by the configuration using tail recursion to sequence multiple tests.
+ */
+static H_UINT aisTest( /* RETURN: nz if input needed */
+ H_COLLECT * h_ctxt, /* IN-OUT: collector context */
+ H_UINT prod, /* IN: production indicator */
+ H_UINT *buffer, /* IN: test data, H_UINT aligned */
+ H_UINT sz) /* IN: size of data in H_UINT */
+{
+ procShared *tps = TESTS_SHARED(h_ctxt);
+ onlineTests *context = (onlineTests *) h_ctxt->havege_tests;
+ procInst *p;
+ H_UINT offs,state=TEST_DONE, tot=0;
+
+ if (context->result!=0)
+ return 0;
+ if (prod==0)
+ p = tps->totTests + context->totIdx;
+ else p = tps->runTests + context->runIdx;
+
+ switch(p->action) {
+ case A_RUN:
+ if (context->pA->procState==TEST_INIT)
+ context->pA->options = p->options;
+ tot = aisProcedureA(h_ctxt, tps, context->pA,
+ buffer, sz, context->szCarry, prod);
+ state = context->pA->procState;
+ break;
+ case B_RUN:
+ if (context->pB->procState==TEST_INIT)
+ context->pB->options = p->options;
+ tot = aisProcedureB(h_ctxt, tps, context->pB,
+ buffer, sz, context->szCarry, prod);
+ state = context->pB->procState;
+ break;
+ }
+ if (state==TEST_INPUT) {
+ context->szCarry = 0;
+ return 1;
+ }
+ context->szTotal += tot;
+ if (prod==0) {
+ if (context->totIdx>=1) /* check for end of tot */
+ return 0;
+ context->totIdx += 1;
+ p = tps->totTests + context->totIdx;
+ }
+ else {
+ if (0==tps->runTests[0].action) /* check for no cont tests */
+ return 0;
+ else if (0!=tps->runTests[1].action) /* check for only 1 cont test */
+ context->runIdx = context->runIdx? 0 : 1;
+ p = tps->runTests + context->runIdx;
+ }
+ switch(p->action) {
+ case A_RUN:
+ context->pA->procState=TEST_INIT;
+ break;
+ case B_RUN:
+ context->pB->procState=TEST_INIT;
+ break;
+ }
+ offs = context->szCarry/BITS_PER_H_UINT;
+ if (offs<sz) {
+ context->szCarry -= offs * BITS_PER_H_UINT;
+ return aisTest(h_ctxt, prod, buffer+offs, sz - offs);
+ }
+ return 1;
+}
+/**
+ * Procedure A input is obtained by copying bits from p->data to p->aux using
+ * p->bridge as position. This realigns the input to a byte boundary and
+ * resolves segmentation issues. Originally implemented in BITSTREAM macros
+ * performance was bad enough to justify serious tuning. Returns the updated
+ * bit offset.
+ */
+/**
+ * The BITSTREAM macros were totally inadequate for the proecedure A needs. These
+ * helpers are used to implement a high performance copyBit().
+ */
+#define COPY_BYTE() {c = (*src<<bit_diff_ls)|(*(src+1)>>bit_diff_rs);src++;}
+#define COPY_FIRST() if ( (int) xfr >= (8 - dst_bits)) {\
+ *dst &= rm[dst_bits];\
+ xfr -= 8 - dst_bits;\
+ }\
+ else {\
+ *dst &= rm[dst_bits] | rm_xor[dst_bits + xfr + 1];\
+ c &= rm[dst_bits + xfr];\
+ xfr = 0;\
+ }\
+ xfr_bytes = xfr>>3;\
+ xfr_bits = xfr&7;\
+ *dst++ |= c;
+/**
+ * Each procedure A repetition moves TEST0_USED + 257*FIPS_USED bits
+ * to the auxilary work space - a little more than 1MB
+ */
+static H_UINT copyBits( /* RETURN: updated bit offset */
+ procA *p, /* IN-OUT: the context */
+ H_UINT offs, /* IN: the input bit offset */
+ H_UINT sz) /* IN: number of bits to copy */
+{
+ H_UINT avail = p->range;
+ H_UINT need = sz - p->bridge;
+ H_UINT xfer, xfr;
+
+ offs %= avail;
+ xfer = (avail-offs)<need? (avail-offs) : need;
+ if ((xfr = xfer)!=0) {
+ static const H_UINT8 rm[] = { 0x55, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ static const H_UINT8 rm_xor[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 };
+ H_UINT8 *src = p->data+(offs>>3);
+ H_UINT8 *dst = p->aux +(p->bridge>>3);
+ H_UINT8 src_bits = offs&7;
+ H_UINT8 dst_bits = p->bridge&7;
+ H_UINT xfr_bytes = xfr>>3;
+ H_UINT xfr_bits = xfr&7;
+ H_UINT8 c;
+
+ if (src_bits==dst_bits) {
+ if (src_bits!=0){
+ c = rm_xor[dst_bits] & *src++;
+ COPY_FIRST();
+ }
+ if (xfr_bytes!=0) {
+ memcpy(dst, src, xfr_bytes);
+ src += xfr_bytes;
+ dst += xfr_bytes;
+ }
+ if (xfr_bits) {
+ *dst &= rm_xor[xfr_bits];
+ *dst |= rm[xfr_bits] & *src++;
+ }
+ }
+ else {
+ H_UINT bit_diff_ls, bit_diff_rs;
+ if (src_bits>dst_bits) {
+ bit_diff_ls = src_bits - dst_bits;
+ bit_diff_rs = 8 - bit_diff_ls;
+ COPY_BYTE();
+ c &= rm_xor[dst_bits];
+ }
+ else {
+ bit_diff_rs = dst_bits - src_bits;
+ bit_diff_ls = 8 - bit_diff_rs;
+ c = *src >> bit_diff_rs & rm_xor[dst_bits];
+ }
+ COPY_FIRST();
+ while (xfr_bytes-- != 0) {
+ COPY_BYTE();
+ *dst++ = c;
+ }
+ if (xfr_bits!=0) {
+ COPY_BYTE();
+ c &= rm[xfr_bits];
+ *dst &= rm_xor[xfr_bits];
+ *dst |= c;
+ }
+ }
+ }
+ p->bridge += xfer;
+ if (p->bridge>=sz) {
+ p->bytesUsed += sz>>3;
+ p->bridge = 0;
+ p->testState = TEST_EVAL;
+ }
+ return offs + xfer;
+}
+/**
+ * Procedure A tests 1 through 4 correspond to the fips140-1 tests. These tests
+ * are conducted on the same input stream, so the calculations can be
+ * done in parallel.
+ */
+#define FIPS_ADD() {\
+ if (runLength < 5)\
+ runs[runLength + (6*current)]++;\
+ else runs[5 + (6*current)]++;\
+ }
+
+static H_UINT fips140( /* RETURN: updated bit offset */
+ procShared *tps, /* IN: shared data */
+ procA *p, /* IN-OUT: the context */
+ H_UINT offs, /* IN: starting offset */
+ H_UINT tid) /* IN: test id */
+{
+ H_UINT poker[16]; /* counters for poker test */
+ H_UINT ones; /* counter for monbit test */
+ H_UINT runs[12]; /* counters for runs tests */
+ H_UINT runLength; /* current run length */
+ H_UINT maxRun; /* largest run encountered */
+ H_UINT current; /* current bit */
+ H_UINT last; /* last bit index */
+ H_UINT c, i, j, k;
+
+ switch(p->testState) {
+ case TEST_INIT:
+ p->testState = TEST_INPUT;
+ p->bridge = 0;
+ /* fallthrough */
+ case TEST_INPUT:
+ offs = copyBits(p, offs, FIPS_USED);
+ if (p->testState!=TEST_EVAL)
+ break;
+ /* fallthrough */
+ case TEST_EVAL:
+ maxRun = ones = runLength = 0;
+ memset(poker, 0, 16*sizeof(H_UINT));
+ memset(runs, 0, 12*sizeof(H_UINT));
+ {
+ BITSTREAM_OPEN(p->aux,0);
+ last = BITSTREAM_BIT();
+ for (c=i=0;i<FIPS_USED;i++) {
+ current = BITSTREAM_BIT();
+ if (current==last) {
+ if (++runLength>maxRun)
+ maxRun = runLength;
+ }
+ else {
+ FIPS_ADD();
+ runLength = 0;
+ last = current;
+ }
+ c += c + current;
+ ones += current;
+ if (bitstream_in==1) {
+ poker[c&15] += 1;
+ c = 0;
+ }
+ else if (bitstream_in==16)
+ poker[c] += 1;
+ BITSTREAM_NEXT();
+ }
+ FIPS_ADD();
+ }
+ /* 1 = monobit test */
+ k = (ones >= FIPS_ONES_HIGH || ones <= FIPS_ONES_LOW)? 1 : 0;
+ p->results[tid].testResult = k | (1<<8);
+ p->results[tid++].finalValue = ones;
+ /* 2 = poker test */
+ for(j=k=0;j<16;j++) k += poker[j]*poker[j];
+ j = (k <= FIPS_POKER_LOW || k >= FIPS_POKER_HIGH)? 1 : 0;
+ p->results[tid].testResult = j | (2<<8);
+ p->results[tid++].finalValue = k;
+ /* 3 = runs test */
+ for(i=j=k=0;j<12;j++)
+ if (runs[j] < tps->fips_low[j%6] || runs[j] > tps->fips_high[j%6]) {
+ k |= 1;
+ i = runs[j];
+ }
+ p->results[tid].testResult = k | (3<<8);
+ p->results[tid++].finalValue = i;
+ /* 4 = max run length */
+ k = maxRun>=FIPS_MAX_RUN? 1 : 0;
+ p->results[tid].testResult = k | (4<<8);
+ p->results[tid++].finalValue = maxRun;
+ p->testRun = tid;
+ p->testState = TEST_DONE;
+ }
+ return offs;
+}
+/**
+ * Procedure A disjointness test on 48 bit strings. Rejection probability for ideal
+ * RNG is 2e^-17
+ */
+static H_UINT test0( /* RETURN: updated bit offset */
+ procA *p, /* IN-OUT: the context */
+ H_UINT offs, /* IN: starting bit offset */
+ H_UINT tid) /* IN: test id */
+{
+ H_UINT i, j;
+
+ switch(p->testState) {
+ case TEST_INIT:
+ p->testState = TEST_INPUT;
+ p->bridge = 0;
+ /* fallthrough */
+ case TEST_INPUT:
+ offs = copyBits(p, offs, TEST0_USED);
+ if (p->testState!=TEST_EVAL)
+ break;
+ /* fallthrough */
+ case TEST_EVAL:
+ qsort(p->aux, TEST0_LENGTH, 6, test0cmp);
+ for (i=6,j=0;i<TEST0_LENGTH && j==0;i+=6)
+ if (!memcmp(p->aux+i-6, p->aux+i, 6)) {
+ j=1;
+ }
+ p->results[tid].testResult = j;
+ p->results[tid++].finalValue = i;
+ p->testRun = tid;
+ p->testState = TEST_DONE;
+ }
+ return offs;
+}
+/**
+ * Comparison method for the test0 sort
+ */
+static int test0cmp(const void *aa, const void *bb)
+{
+ return memcmp(aa,bb,6);
+}
+/**
+ * Procedure A autocorrelation test. Brutal bit twiddling. Uses same
+ * data as FIPS - no update to bit offset
+ */
+static H_UINT test5( /* RETURN: updated bit offset */
+ procA *p, /* IN-OUT: the context */
+ H_UINT offs, /* IN: starting bit offset */
+ H_UINT tid) /* IN: test id */
+{
+ H_UINT8 *dp = (H_UINT8 *)p->aux;
+ H_UINT j, k, max, tau, Z_tau;
+
+ /**
+ * Because this test is so slow it can be skipped on one or more repetitions
+ */
+ if (0 != (p->options & A_CYCLE)) {
+ j = p->options & A_CYCLE;
+ if (j==0 || ((tid-1)/5 % j)!=0) {
+ p->results[tid++].testResult = 0xff00;
+ p->testRun = tid;
+ p->testState = TEST_DONE;
+ return offs;
+ }
+ }
+ /**
+ * This test always uses the same data as test1 through test4
+ */
+ for (max = k = 0,tau=1;tau<=TEST5_LENGTH;tau++){
+ Z_tau = abs( (int) test5XOR(dp, tau) - 2500);
+ if (Z_tau > max) {
+ max = Z_tau;
+ k = tau - 1;
+ }
+ }
+ dp += TEST5_LENGTH/8;
+ Z_tau = test5XOR(dp, k + 1);
+ j = 5<<8;
+ if (( Z_tau <= 2326) || ( Z_tau >= 2674))
+ j |= 1;
+
+ p->results[tid].testResult = j;
+ p->results[tid++].finalValue = Z_tau;
+ p->testRun = tid;
+ p->testState = TEST_DONE;
+ return offs;
+}
+/**
+ * The test5 reference implementation looks something like this:
+ *
+ * for(i=0,j=shift;i<TEST5_LENGTH;i++,j++)
+ * rv += 1 & (((src[i>>3]>>(i & 7))) ^ ((src[j>>3]>>(j & 7))));
+ * return rv;
+ *
+ * A high performance optimization using multi-byte casts is 3x as fast as the above but blows up
+ * because of alignment issues (leftovers from the test0 implementation)
+ * The optimized single byte optimization is 2x as fast as the above but uses no alignment games
+ */
+static H_UINT test5XOR(H_UINT8 *src, H_UINT shift)
+{
+ H_UINT8 *src1;
+ H_UINT i,rest, rv;
+
+ src1 = src + (shift>>3);
+ shift &= 7;
+ rest = 8 - shift;
+ for(i=rv=0;i<(TEST5_LENGTH>>3);i++) {
+ H_UINT8 lw = *src++;
+ H_UINT8 rw = *src1++;
+ H_UINT8 w;
+
+ for (w = (lw & (0xff>>shift)) ^ (rw>>shift);w!=0;w>>=1)
+ rv += w & 1;
+ for (w = (lw>>rest) ^ (*src1 & (0xff>>rest));w!=0;w>>=1)
+ rv += w & 1;
+ }
+ return rv;
+}
+/**
+ * Procedure B uniform distribution test for parameter set (1,100000,0.25). Very simple, just
+ * count bits. Fixed input size, deadman not needed
+ */
+#define SIDEWAYS_ADD(c,i) {H_UINT in = i;\
+ in -= ((in >> 1) & 0x55555555);\
+ in = (in & 0x33333333) + ((in >> 2) & 0x33333333);\
+ c=(((in + (in >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;\
+ }
+
+static H_UINT test6a( /* RETURN: bit offset */
+ procB *p, /* IN-OUT: the context */
+ H_UINT offs, /* IN: starting bit offset */
+ H_UINT tid) /* IN: test id */
+{
+ H_UINT r = p->range - offs;
+ H_UINT i=0,j=p->bridge;
+
+ switch(p->testState) {
+ case TEST_INIT:
+ j = p->counter[0] = 0;
+ p->testState = TEST_INPUT;
+ /* fallthrough */
+ case TEST_INPUT:
+ {
+ BITSTREAM_OPEN(p->noise,offs);
+ H_UINT c;
+
+ /* align to a byte boundary, then shift gears to gobble bytes */
+ while(i < r && j < AIS_LENGTH && bitstream_in != 0x80){
+ p->counter[0] += BITSTREAM_BIT();BITSTREAM_NEXT();
+ i++;j++;
+ }
+ /* align to a word boundary, then shift gears to gobble words */
+ while((i+8) < r && (j+8) < AIS_LENGTH) {
+ if (0==((char *)bitstream_src - (char *)p->noise) % sizeof(H_UINT))
+ break;
+ SIDEWAYS_ADD(c, *bitstream_src++);
+ p->counter[0] += c;
+ i+=8;j+=8;
+ }
+ /* gobble all words available */
+ while((i+BITS_PER_H_UINT) < r && (j+BITS_PER_H_UINT) < AIS_LENGTH) {
+ SIDEWAYS_ADD(c, *((H_UINT *)bitstream_src));
+ bitstream_src += sizeof(H_UINT);
+ p->counter[0] += c;
+ i+=BITS_PER_H_UINT;j+=BITS_PER_H_UINT;
+ }
+ /* shift back to bits & cleanup the leftovers */
+ for(;i < r && j < AIS_LENGTH;i++,j++) {
+ p->counter[0] += BITSTREAM_BIT();BITSTREAM_NEXT();
+ }
+ p->bitsUsed += i;
+ if (j < AIS_LENGTH) {
+ p->bridge = j;
+ break;
+ }
+ }
+ /* fallthrough */
+ case TEST_EVAL:
+ p->results[p->testNbr].finalValue = (double)(p->counter[0]) / (double) AIS_LENGTH;
+ r = tid << 8;
+ if (p->results[p->testNbr].finalValue <= 0.25 || p->results[p->testNbr].finalValue >= 0.75)
+ r |= 1;
+ p->results[p->testNbr++].testResult = r;
+ p->testState = TEST_DONE;
+ }
+ return i+offs;
+}
+/**
+ * Context is saved and restored using inactive members of the anchor.
+ */
+#define RESTORE8(a,b,c,d) a=p->bridge;b=p->full;c=p->einsen[0];\
+ d=p->results[p->testNbr].finalValue
+#define SAVE8(a,b,c,d) p->bridge=a;p->full=b;p->einsen[0]=c;\
+ p->results[p->testNbr].finalValue = d
+/**
+ * Procedure B entropy estimator (Coron). Find the distribution of the distance between
+ * bytes and their predecessors. Fixed input size, no deadman needed.
+ */
+static H_UINT test8( /* RETURN: bit offset */
+ procShared *tps, /* IN-OUT: shared data */
+ procB *p, /* IN-OUT: the context */
+ H_UINT offs, /* IN: starting bit offset */
+ H_UINT tid) /* IN: test id */
+{
+ H_UINT hilf, j, k, r, i=0;
+ double TG=0.0;
+
+ switch(p->testState) {
+ case TEST_INIT:
+ memset(p->lastpos, 0, 256*sizeof(H_UINT));
+ SAVE8(0,0,0,0.0);
+ p->testState = TEST_INPUT;
+ /* fallthrough */
+ case TEST_INPUT:
+ RESTORE8(k,j,hilf,TG);
+ r = p->range - offs;
+ {
+ H_UINT align;
+ /* gobble bits up to a byte boundary */
+ BITSTREAM_OPEN(p->noise,offs);
+ for(;j<8 && i<r && bitstream_in!=0x80;i++,j++) {
+ hilf += hilf+(BITSTREAM_BIT());BITSTREAM_NEXT();
+ }
+ align = (j &= 7);
+ while(i<r) {
+ if (j==0 && (i+8)<r) { /* gobble a byte */
+ hilf = (0xff & (bitstream_src[0]<<(8-align))) | (bitstream_src[1]>>align);
+ bitstream_src++;i+=8;j=8;
+ }
+ for(;j<8 && i<r;i++,j++) { /* gobble loose bits */
+ hilf += hilf+(BITSTREAM_BIT());BITSTREAM_NEXT();
+ }
+ if (j!=8)
+ break;
+ if (k<Q)
+ p->lastpos[hilf] = k++;
+ else {
+ TG += tps->G[k - p->lastpos[hilf]];
+ p->lastpos[hilf] = k++;
+ if (k==(K+Q)) {
+ p->testState = TEST_EVAL;
+ break;
+ }
+ }
+ j = hilf = 0;
+ }
+ if (p->testState==TEST_INPUT) {
+ SAVE8(k,j,hilf,TG);
+ }
+ }
+ p->bitsUsed += i;
+ if (p->testState == TEST_INPUT)
+ break;
+ /* fallthrough */
+ case TEST_EVAL:
+ tps->lastCoron = p->results[p->testNbr].finalValue = TG/(double)K;
+ r = tid<<8;
+ if (p->results[p->testNbr].finalValue <= 7.967)
+ r |= 1;
+ p->results[p->testNbr++].testResult = r;
+ p->testState = TEST_DONE;
+ }
+ return i+offs;
+}
+#endif
diff --git a/src/havegetest.h b/src/havegetest.h
new file mode 100644
index 0000000..8e9ac28
--- /dev/null
+++ b/src/havegetest.h
@@ -0,0 +1,225 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2012-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HAVEGETEST_H
+#define HAVEGETEST_H
+/**
+ * The haveged test suite is built from the 8 tests specified in AIS-31
+ * organized into test procedure A and test procedure B and structured
+ * as state machines capable of processing segmented input streams.
+ */
+#include "havegecollect.h"
+/**
+ * All individual tests and the test procedures use the following
+ * simple state machine to manage input.
+ */
+typedef enum {
+ TEST_INIT, /* initialize test (internal) */
+ TEST_INPUT, /* test input needed */
+ TEST_EVAL, /* evaluating results (internal) */
+ TEST_DONE, /* test complete */
+ TEST_RETRY, /* retry the test */
+ TEST_IGNORE, /* ignore failure and continue */
+ TEST_FAIL /* Test has failed */
+ } TEST_STATE;
+/**
+ * AIS-31 procedure A uses the FIPS140-1 as test1 thru test4. A disjointedness test is
+ * used as test0 and a autocorrelation test is used as test5. test0 is executed only
+ * once, the other tests are repeated in sequence 257 times.
+ */
+#define AIS_A_REPS 257 /* reps for test1 through test 5 */
+/**
+ * Constants for the fips tests. Note AIS-31 v1 uses the unamended FIPS test limits
+ */
+#define FIPS_USED 20000
+#ifndef USE_AMENDED_FIPS
+#define FIPS_MAX_RUN 34
+#define FIPS_ONES_LOW 9654
+#define FIPS_ONES_HIGH 10346
+#define FIPS_POKER_LOW 1562822 /* 1.03 */
+#define FIPS_POKER_HIGH 1580438 /* 57.4 */
+#define FIPS_RUNS_LOW 2267,1079,502,223,90,90
+#define FIPS_RUNS_HIGH 2733,1421,748,402,223,223
+#else
+#define FIPS_MAX_RUN 25
+#define FIPS_ONES_LOW 9725
+#define FIPS_ONES_HIGH 10275
+#define FIPS_POKER_LOW 1576928 /* 2.16 */
+#define FIPS_POKER_HIGH 1576928 /* 46.17 */
+#define FIPS_RUNS_LOW 2315,1114,525,240,103,103
+#define FIPS_RUNS_HIGH 2685,1386,723,384,209,209
+#endif
+/**
+ * test 0 consumes 64k * 48 bits
+ */
+#define TEST0_LENGTH 65536
+#define TEST0_USED (TEST0_LENGTH * 48)
+#define TEST5_LENGTH 5000
+/**
+ * Fixed size input for procedure A
+ */
+#define AIS_A_SIZE (TEST0_USED+(2500*257))
+/**
+ * AIS-31 procedure A results
+ */
+typedef struct {
+ H_UINT testResult; /* id 8 bits, pass/fail 8bits */
+ H_UINT finalValue; /* end result */
+} resultA;
+/**
+ * AIS-31 procedure A context. Options are defined in haveged.h
+ * This puppy weighs in at ~3 MB.
+ */
+typedef struct {
+ H_UINT8 *data; /* input for test */
+ H_UINT range; /* number of bits of input */
+ H_UINT procState; /* procedure state */
+ H_UINT procRetry; /* retry indication */
+ H_UINT testId; /* test selector 0-5 */
+ H_UINT testRun; /* test index 1 - 1285 */
+ H_UINT testState; /* FSM state of current test */
+ H_UINT bridge; /* index for data bridge */
+ H_UINT bytesUsed; /* number of bytes used */
+ H_UINT options; /* duty cycle for test5 */
+ H_UINT8 aux[TEST0_USED]; /* extra work space */
+ resultA results[1286]; /* test results */
+ } procA;
+/**
+ * AIS-31 procedure B is a set of multinomial distribution tests
+ * and an entropy estimate (Coron' test). The distribution tests,
+ * test6 and test7, require at least AIS_LENGTH sequences of 1, 2
+ * 4, and 8 bits.
+ */
+/*
+ * Bit range of AIS-31 procedure B distribution tests
+ */
+#define AIS_LENGTH 100000
+/**
+ * AIS-31 test8 constants (Coron's test)
+ */
+#define Q 2560
+#define K 256000
+#define LN2 0.69314718055994530941
+/**
+ * AIS-31 procedure B results
+ */
+typedef struct {
+ H_UINT testResult; /* id 8 bits, pass/fail 8bits */
+ double finalValue; /* final value */
+ } resultB;
+/**
+ * AIS-31 procedure B context, a svelt 1.25 KB
+ */
+typedef struct {
+ H_UINT *noise; /* input for test */
+ H_UINT range; /* number of bits of input */
+ H_UINT procState; /* procedure state */
+ H_UINT procRetry; /* retry indication */
+ H_UINT testId; /* test selector 6-8 */
+ H_UINT testNbr; /* current test number */
+ H_UINT testState; /* FSM state of current test */
+ H_UINT seq; /* aisSeq() sequence needed */
+ H_UINT bitsUsed; /* bits used by procedure */
+ H_UINT bridge; /* data bridge test6,7 */
+ H_UINT counter[8]; /* sequence lengths */
+ H_UINT einsen[8]; /* sequence counts (ones) */
+ H_UINT full; /* sequence flags */
+ H_UINT lastpos[256]; /* counters for test 8 */
+ H_UINT options; /* RFU */
+ resultB results[9]; /* test results */
+ } procB;
+/**
+ * Testing options
+ */
+#define A_CYCLE 0x000001ff /* test5 duty cycle */
+#define A_WARN 0x00000200 /* Only warn of A fails */
+#define A_RUN 0x00000400 /* Run procedure A */
+#define A_OPTIONS 0x000003ff
+#define B_WARN 0x00001000 /* Only warn of B fails */
+#define B_RUN 0x00002000 /* Run proceure B */
+#define B_OPTIONS 0x00001000
+#define X_OPTIONS 0x000f0000 /* isolated test index */
+#define X_RUN 0x00100000 /* diagnostic isolated test */
+/**
+ * A test procedure run consists of an indicator and options
+ */
+typedef struct {
+ H_UINT action; /* action code A_RUN, B_RUN */
+ H_UINT options; /* WARN and other options */
+ } procInst;
+
+/**
+ * Services provided
+ */
+typedef int (*ptrDiscard)(H_COLLECT *rdr);
+typedef void (*ptrReport)(H_COLLECT * h_ctxt, H_UINT action, H_UINT prod, H_UINT state, H_UINT ct);
+typedef int (*ptrRun)(H_COLLECT *rdr, H_UINT prod);
+
+/**
+ * A test procedure is associated with a collection buffer. Some
+ * resources are shared by all collection buffers. This includes
+ * roll-your-own vtable used to avoid polluting the RNG name space
+ * This structure ends up in hptr->testData
+ */
+typedef struct {
+ ptrDiscard discard; /* release test resources */
+ ptrRun run; /* run test suite */
+ ptrReport report; /* report test results */
+ H_UINT options; /* verbosity, etc. */
+ H_UINT testsUsed; /* tests used */
+ procInst totTests[2]; /* tot tests to run */
+ procInst runTests[2]; /* production tests to run */
+ H_UINT procReps; /* Number of A repetitions */
+ H_UINT fips_low[6]; /* low runs thresholds */
+ H_UINT fips_high[6]; /* high runs thresholds */
+ char totText[8]; /* tot test text rep */
+ char prodText[8]; /* production test text rep */
+ H_UINT meters[H_OLT_PROD_B_P+1]; /* test counters */
+ double lastCoron; /* last test8 result */
+ double *G; /* test8 lookup table */
+} procShared;
+/**
+ * How to get test context and shared data from H_COLLECT
+ */
+#define TESTS_CONTEXT(c) (onlineTests *)(c->havege_tests)
+#define TESTS_SHARED(c) (procShared *)(((H_PTR)(c->havege_app))->testData)
+/**
+ * Online testing context - one per collector. Note szTotal is for diagnostic
+ * use only, no effort is made to account for overflow.
+ */
+typedef struct {
+ H_UINT result; /* nz if failed */
+ H_UINT totIdx; /* tot test idx */
+ H_UINT runIdx; /* run test idx */
+ H_UINT szCarry; /* bits carried in next proc */
+ H_UINT szTotal; /* total bits processed */
+ procA *pA; /* procedure A instance */
+ procB *pB; /* procedure B instance */
+} onlineTests;
+/**
+ * Default options are to run the tot tests.
+ */
+#define DEFAULT_TEST_OPTIONS "ta8b"
+/**
+ * Public interface
+ */
+int havege_test(procShared *tps, H_PARAMS *params);
+
+#endif
diff --git a/src/havegetune.c b/src/havegetune.c
new file mode 100644
index 0000000..f558e0d
--- /dev/null
+++ b/src/havegetune.c
@@ -0,0 +1,926 @@
+/**
+ ** Determine HAVEGE environment
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **
+ */
+/**
+ * This compile unit implements automatic tuning for the havege algorithm. Two
+ * general methods are used CPUID (intel specific) and VFS (Linux specific). The
+ * best result of the available methods is returned.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+#include "havegetune.h"
+/**
+ * Text representations of build options
+ */
+#define BUILD_CLOCK 'C'
+#define BUILD_DIAGS 'D'
+#define BUILD_CPUID 'I'
+#define BUILD_THREADS 'M'
+#define BUILD_OLT 'T'
+#define BUILD_VFS 'V'
+/**
+ * Text representations of TOPO_MAP sources
+ */
+static const char *topoReps[] = {
+ "D", /* SRC_DEFAULT 0x00001 */
+ "P", /* SRC_PARAM 0x00002 */
+ "A6", /* SRC_CPUID_AMD6 0x00004 */
+ "A5", /* SRC_CPUID_AMD5 0x00008 */
+ "L2", /* SRC_CPUID_INTEL2 0x00010 */
+ "L4", /* SRC_CPUID_INTEL4 0x00020 */
+ "V", /* SRC_VFS_INDEX 0x00040 */
+ "", /* not used 0x00080 */
+ "C", /* SRC_CPUID_PRESENT 0x00100 */
+ "H", /* SRC_CPUID_HT 0x00200 */
+ "A", /* SRC_CPUID_AMD 0x00400 */
+ "A8", /* SRC_CPUID_AMD8 0x00800 */
+ "B", /* SRC_CPUID_LEAFB 0x01000 */
+ "4", /* SRC_CPUID_LEAF4 0x02000 */
+ "VS", /* SRC_VFS_STATUS 0x04000 */
+ "VO" /* SRC_VFS_ONLINE 0x08000 */
+ "VI", /* SRC_VFS_CPUINFO 0x10000 */
+ "VC", /* SRC_VFS_CPUDIR 0x20000 */
+ 0
+ };
+/**
+ * Local debugging
+ */
+#if 0
+#define TUNE_DEBUG(...) fprintf(stderr,__VA_ARGS__)
+#define TUNE_DUMP 1
+static void cfg_dump(HOST_CFG *anchor);
+#else
+#define TUNE_DEBUG(...)
+#endif
+
+/**
+ * Local prototypes
+ */
+#ifdef TUNING_VFS_ENABLE
+static void cfg_bitClear(TOPO_MAP *m);
+static int cfg_bitCount(TOPO_MAP *m);
+#endif
+static void cfg_bitDecode(char *dest, const char **reps, H_UINT value, H_UINT size);
+#if 0
+static void cfg_bitDisplay(TOPO_MAP *m);
+#endif
+static int cfg_bitIntersect(TOPO_MAP *m, TOPO_MAP *t);
+static void cfg_bitMerge(TOPO_MAP *m,TOPO_MAP *t);
+static int cfg_bitNext(TOPO_MAP *m, int n);
+static void cfg_bitSet(TOPO_MAP *m, int n);
+static void cfg_cacheAdd(HOST_CFG *anchor, H_UINT src, H_UINT cpu,
+ H_UINT level, H_UINT type, H_UINT kb);
+static void cfg_cpuAdd(HOST_CFG *anchor, H_UINT src, CPU_INST *INST);
+/**
+ * If cpuid not present, no need to generate the code
+ */
+#ifndef CPUID
+#undef TUNING_CPUID_ENABLE
+#endif
+
+#ifdef TUNING_CPUID_ENABLE
+/************************* CPUID support ***************************************/
+/**
+ * Register names
+ */
+typedef enum {
+ EAX, EBX, ECX, EDX
+} CPUID_REGNAMES;
+
+#define CPUID_CONFIG(a) cpuid_config(a)
+#define CPUID_VENDOR(r) *((H_UINT *)s) = regs[r];s+= sizeof(H_UINT)
+/**
+ * Local CPUID prototypes
+ */
+#if defined (GCC_VERSION) && GCC_VERSION >= 40400
+static void cpuid(int fn, int sfn, H_UINT *regs) __attribute__((optimize(0)));
+#else
+static void cpuid(int fn, int sfn, H_UINT *regs);
+#endif
+static void cpuid_config(HOST_CFG *anchor);
+static void cpuid_configAmd(HOST_CFG *anchor, CPU_INST *w);
+static void cpuid_configIntel(HOST_CFG *anchor, CPU_INST *w);
+static void cpuid_configIntel2(HOST_CFG *anchor, CPU_INST *w, H_UINT *regs);
+static void cpuid_configIntel4(HOST_CFG *anchor, CPU_INST *w, H_UINT *regs);
+#else
+#define CPUID_CONFIG(a)
+#endif
+/************************ /CPUID support ***************************************/
+/************************ VFS support ***************************************/
+#ifdef TUNING_VFS_ENABLE
+
+#define VFS_LINESIZE 256
+/**
+ * Filter function used by configuration
+ */
+typedef int (*pFilter)(HOST_CFG *pAnchor, char *input);
+typedef int (*pDirFilter)(HOST_CFG *pAnchor, char *input, H_UINT *pArg);
+/**
+ * Definitions
+ */
+#define VFS_CONFIG(a) vfs_config(a)
+/**
+ * Local filesystem prototypes
+ */
+static void vfs_config(HOST_CFG *anchor);
+static int vfs_configCpuDir(HOST_CFG *anchor, char *input, H_UINT *pArg);
+static int vfs_configCpuInfo(HOST_CFG *anchor, char *input);
+static int vfs_configDir(HOST_CFG *pAnchor, char *path, pDirFilter filter, H_UINT *pArg);
+static int vfs_configFile(HOST_CFG *anchor, char *path, pFilter filter);
+static int vfs_configInfoCache(HOST_CFG *pAnchor, char *input, H_UINT *pArg);
+static int vfs_configOnline(HOST_CFG *anchor, char *input);
+static int vfs_configInt(HOST_CFG *anchor, char *input);
+static int vfs_configStatus(HOST_CFG *anchor, char *input);
+static int vfs_configType(HOST_CFG *anchor, char *input);
+
+static void vfs_parseList(TOPO_MAP *map, char *input);
+static void vfs_parseMask(TOPO_MAP *map, char *input);
+#else
+#define VFS_CONFIG(a)
+#endif
+/************************* /VFS support ***************************************/
+
+/**
+ * Get tuning values for collector
+ */
+void havege_tune( /* RETURN: none */
+ HOST_CFG *anchor, /* OUT: tuning info */
+ H_PARAMS *param) /* IN: config parameters */
+{
+ char *bp = anchor->buildOpts;
+ int i;
+
+ /**
+ * Capture build options
+ */
+#ifdef __GNUC__
+ bp += snprintf(bp, 24, "gcc %d.%d.%d ", __GNUC__ ,__GNUC_MINOR__ , __GNUC_PATCHLEVEL__);
+#endif
+#if defined(ENABLE_CLOCK_GETTIME)
+ *bp++ = BUILD_CLOCK;
+#endif
+#if defined(RAW_IN_ENABLE) || defined(RAW_OUT_ENABLE)
+ *bp++ = BUILD_DIAGS;
+#endif
+#ifdef TUNING_CPUID_ENABLE
+ *bp++ = BUILD_CPUID;
+#endif
+#if NUMBER_CORES>1
+ *bp++ = BUILD_THREADS;
+#endif
+#ifdef ONLINE_TESTS_ENABLE
+ *bp++ = BUILD_OLT;
+#endif
+#ifdef TUNING_VFS_ENABLE
+ *bp++ = BUILD_VFS;
+#endif
+ *bp = 0;
+ /**
+ * Virtual file system setup
+ */
+ anchor->procfs = param->procFs==NULL? "/proc" : param->procFs;
+ anchor->sysfs = param->sysFs==NULL? "/sys" : param->sysFs;
+ /**
+ * The order determines preference
+ */
+ if (param->icacheSize != 0)
+ cfg_cacheAdd(anchor, SRC_PARAM, -1, 1, 'I', param->icacheSize);
+ if (param->dcacheSize != 0)
+ cfg_cacheAdd(anchor, SRC_PARAM, -1, 1, 'D', param->dcacheSize);
+ /**
+ * Bypass configuration if entirely specified
+ */
+ if (param->icacheSize == 0 || param->dcacheSize == 0) {
+ CPUID_CONFIG(anchor);
+ VFS_CONFIG(anchor);
+ cfg_cacheAdd(anchor, SRC_DEFAULT, -1, 1, 'I', GENERIC_ICACHE);
+ cfg_cacheAdd(anchor, SRC_DEFAULT, -1, 1, 'D', GENERIC_DCACHE);
+ }
+ /**
+ * Make sure there is at least 1 cpu instance. cpus configuration is considered
+ * homogeneous so only the first will be reported/used.
+ */
+ if (0 == anchor->ctCpu)
+ cfg_cpuAdd(anchor, 0, NULL);
+ cfg_bitDecode(anchor->cpuOpts, topoReps, anchor->cpus[0].cpuMap.source, SZ_CPUREP);
+ #ifdef TUNE_DUMP
+ cfg_dump(anchor);
+ #endif
+ anchor->d_tune = anchor->i_tune = MAX_CACHES+2;
+ for (i=0;i<anchor->ctCache;i++) {
+ if (anchor->caches[i].level==1) {
+ switch(anchor->caches[i].type) {
+ case 'I': case 'T':
+ if (i < (int)anchor->i_tune)
+ anchor->i_tune = i;
+ break;
+ case 'D':
+ if (i < (int)anchor->d_tune)
+ anchor->d_tune = i;
+ break;
+ }
+ }
+ }
+ cfg_bitDecode(anchor->icacheOpts, topoReps,
+ anchor->caches[anchor->i_tune].cpuMap.source, SZ_CACHEREP);
+ cfg_bitDecode(anchor->dcacheOpts, topoReps,
+ anchor->caches[anchor->d_tune].cpuMap.source, SZ_CACHEREP);
+ TUNE_DEBUG("havege_tune %d/%d\n", anchor->i_tune, anchor->d_tune);
+}
+#ifdef TUNING_VFS_ENABLE
+/**
+ * Return number of bits set in map
+ */
+static void cfg_bitClear( /* RETURN : None */
+ TOPO_MAP *m) /* IN: bitmap */
+{
+ memset(&m->bits[0], 0, MAX_BIT_IDX * sizeof(H_UINT));
+}
+/**
+ * Return number of bits set in map
+ */
+static int cfg_bitCount( /* RETURN : None */
+ TOPO_MAP *m) /* IN: bitmap */
+{
+ int n, ct=0;
+
+ for(n=-1;(n=cfg_bitNext(m,n))!=-1;ct++) ;
+ return ct;
+}
+#endif
+/**
+ * decode bit representation
+ */
+static void cfg_bitDecode( /* RETURN: None */
+ char *dest, /* OUT: target */
+ const char **reps, /* IN: codes */
+ H_UINT value, /* IN: value to decode */
+ H_UINT size) /* IN: max range */
+{
+ H_UINT i=0;
+ const char *s;
+
+ size -= 1;
+ while(value!= 0 && *reps != 0) {
+ s = *reps++;
+ if ((value & 1) != 0) {
+ if (i>0 && i < size)
+ dest[i++] = ' ';
+ while(*s != 0 && i < size)
+ dest[i++] = *s++;
+ }
+ value >>= 1;
+ }
+ dest[i] = 0;
+}
+#if 0
+/**
+ * Display topo bit map - cpuset(7) convention is big-endian
+ */
+static void cfg_bitDisplay( /* RETURN : None */
+ TOPO_MAP *m) /* IN: bitmap */
+{
+ int n;
+
+ for(n=m->msw;n>=0 && n < (int)MAX_BIT_IDX;n--)
+ printf(" %08x", m->bits[n]);
+}
+#endif
+/**
+ * Test if maps intersect
+ */
+static int cfg_bitIntersect( /* RETURN: None */
+ TOPO_MAP *m, /* OUT: bitmap */
+ TOPO_MAP *t) /* IN: bit to set */
+{
+ H_UINT i;
+
+ for (i=0;i < MAX_BIT_IDX;i++)
+ if (0!=(m->bits[i] & t->bits[i]))
+ return 1;
+ return 0;
+}
+/**
+ * Merge two maps
+ */
+static void cfg_bitMerge( /* RETURN: None */
+ TOPO_MAP *m, /* OUT: bitmap */
+ TOPO_MAP *t) /* IN: bits to set */
+{
+ int i;
+
+ for (i=0;i<(int)MAX_BIT_IDX;i++) {
+ m->bits[i] |= t->bits[i];
+ if (0 != m->bits[i] && i > m->msw)
+ m->msw = i;
+ }
+}
+/**
+ * Find next bit in topo bit map
+ */
+static int cfg_bitNext ( /* RETURN: index of next bit or -1 */
+ TOPO_MAP *m, /* IN: bitmap */
+ int n) /* IN: prev bit use -1 for first */
+{
+ int bit, word;
+
+ bit = (n+1) % BITS_PER_H_UINT;
+ for(word = (n+1) / BITS_PER_H_UINT;word <= m->msw && word < (int)MAX_BIT_IDX;word++) {
+ for(;bit<(int)BITS_PER_H_UINT; bit++)
+ if (m->bits[word] & 1<< bit)
+ return word * BITS_PER_H_UINT + bit;
+ bit = 0;
+ }
+ return -1;
+}
+/**
+ * Set a bit in the topo bit map
+ */
+static void cfg_bitSet( /* RETURN: None */
+ TOPO_MAP *m, /* OUT: bitmap */
+ int n) /* IN: bit to set */
+{
+ int word;
+
+ word = n / BITS_PER_H_UINT;
+ if (word < (int)MAX_BIT_IDX) {
+ if (word > m->msw)
+ m->msw = word;
+ m->bits[word] |= 1 << (n % BITS_PER_H_UINT);
+ }
+}
+/**
+ * Add cache description to configuration
+ */
+static void cfg_cacheAdd( /* RETURN: None */
+ HOST_CFG *anchor, /* IN-OUT: configuration */
+ H_UINT src, /* IN: source */
+ H_UINT cpu, /* IN: use -1 for all */
+ H_UINT level, /* IN: cache level */
+ H_UINT type, /* IN: cache type */
+ H_UINT kb) /* IN: cache size in kb */
+{
+ int i;
+
+ TUNE_DEBUG("cacheAdd(%x, %d,%d,%d,%c)\n", src, cpu, level, kb, type);
+ if (3 < level || 0 ==kb) return;
+ for(i = 0;i < anchor->ctCache;i++)
+ if (anchor->caches[i].level == level &&
+ anchor->caches[i].type == type &&
+ anchor->caches[i].size == kb)
+ break;
+ if (i >= MAX_CACHES) return;
+ if (-1 == (int)cpu)
+ cfg_bitMerge(&anchor->caches[i].cpuMap, &anchor->pCacheInfo);
+ else cfg_bitSet(&anchor->caches[i].cpuMap, cpu);
+ anchor->caches[i].cpuMap.source |= src;
+ if (i < anchor->ctCache) return;
+ anchor->caches[i].level = level;
+ anchor->caches[i].type = type;
+ anchor->caches[i].size = kb;
+ anchor->ctCache += 1;
+}
+/**
+ * Add cpu description to configuration
+ */
+static void cfg_cpuAdd( /* RETURN: None */
+ HOST_CFG *anchor, /* IN-OUT: configuration */
+ H_UINT src, /* IN: source */
+ CPU_INST *inst) /* IN: instance */
+{
+ int i=0;
+
+ TUNE_DEBUG("cpuAdd(%x)\n", src);
+ if (NULL==inst) {
+ cfg_bitSet(&anchor->cpus[i].cpuMap, 0);
+ anchor->ctCpu = 1;
+ return;
+ }
+ for(i=0;i < anchor->ctCpu;i++)
+ if (0 != cfg_bitIntersect(&anchor->cpus[i].cpuMap, &inst->cpuMap)) {
+ cfg_bitMerge(&anchor->cpus[i].cpuMap, &inst->cpuMap);
+ anchor->cpus[i].cpuMap.source |= src;
+ return;
+ }
+ if (i >= MAX_CPUS) return;
+ memcpy(&anchor->cpus[i], inst, sizeof(CPU_INST));
+ anchor->cpus[i].cpuMap.source = src;
+ anchor->ctCpu += 1;
+}
+#ifdef TUNE_DUMP
+/**
+ * Diagnostic dump
+ */
+static void cfg_dump( /* RETURN: None */
+ HOST_CFG *anchor) /* IN: configuration */
+{
+ int i;
+
+ for(i=0;i < anchor->ctCpu;i++)
+ printf("Cpu: %08x\n",
+ anchor->caches[i].cpuMap.source
+ );
+ for(i = 0;i < anchor->ctCache;i++)
+ printf("Cache: %08x %d, %c, %d\n",
+ anchor->caches[i].cpuMap.source,
+ anchor->caches[i].level,
+ anchor->caches[i].type,
+ anchor->caches[i].size
+ );
+}
+#endif
+
+#ifdef TUNING_CPUID_ENABLE
+/************************* CPUID support ***************************************/
+/**
+ * Wrapper around the cpuid macro to assist in debugging
+ */
+static void cpuid( /* RETURN: none */
+ int fn, /* IN: function code */
+ int sfn, /* IN: subfunction */
+ H_UINT *regs) /* IN-OUT: Workspace */
+{
+ regs[2] = sfn;
+ CPUID(fn, regs);
+}
+/**
+ * Get configuration
+ */
+static void cpuid_config( /* RETURN: none */
+ HOST_CFG *anchor) /* IN-OUT: result */
+{
+ CPU_INST wsp;
+ H_UINT regs[4];
+ char *s;
+
+ if (HASCPUID(regs)) {
+ memset(&wsp, 0, sizeof(CPU_INST));
+ wsp.flags |= SRC_CPUID_PRESENT;
+ cpuid(0x00,0,regs);
+ wsp.maxFn = regs[EAX];
+ s = wsp.vendor;
+ CPUID_VENDOR(EBX);
+ CPUID_VENDOR(EDX);
+ CPUID_VENDOR(ECX);
+ if (regs[EBX] == 0x68747541)
+ wsp.flags |= SRC_CPUID_AMD;
+ (void)cpuid(0x80000000,0,regs);
+ wsp.maxFnx = regs[EAX];
+ (void)cpuid(0x01,0,regs);
+ wsp.signature = regs[EAX];
+ if ((regs[EDX] & (1<<28)) != 0)
+ wsp.flags |= SRC_CPUID_HT;
+ TUNE_DEBUG("cpuid_config %s fn=%d fnx=%x flags=%x\n", (char *)wsp.vendor,
+ wsp.maxFn, wsp.maxFnx, wsp.flags);
+ if (0!=(wsp.flags & SRC_CPUID_AMD))
+ cpuid_configAmd(anchor, &wsp);
+ else cpuid_configIntel(anchor, &wsp);
+ }
+}
+/**
+ * AMD cpuid Configuration. Reference: Publication 25481, Revision 2.34, Sept 2010
+ */
+static void cpuid_configAmd(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ CPU_INST *w) /* IN-OUT: Workspace */
+{
+ H_UINT regs[4];
+ int i, n;
+
+ switch((w->maxFnx&15)) {
+ case 8:
+ cpuid(0x80000008,0,regs);
+ n = 1 + (regs[ECX] & 0xff);
+ for(i=0;i<n;i++)
+ cfg_bitSet(&w->cpuMap, i);
+ cfg_cpuAdd(anchor, SRC_CPUID_AMD8, w);
+ /* fallthrough */
+ case 6:
+ cpuid(0x80000006,0,regs);
+ cfg_cacheAdd(anchor, SRC_CPUID_AMD6, -1, 2, 'U', (regs[ECX]>>16) & 0xffff);
+ cfg_cacheAdd(anchor, SRC_CPUID_AMD6, -1, 3, 'U', ((regs[EDX]>>18) & 0x3fff)<<9);
+ /* fallthrough */
+ case 5:
+ cpuid(0x80000005,0,regs);
+ cfg_cacheAdd(anchor, SRC_CPUID_AMD5, -1, 1, 'D', (regs[ECX]>>24) & 0xff);
+ cfg_cacheAdd(anchor, SRC_CPUID_AMD5, -1, 1, 'I', (regs[EDX]>>24) & 0xff);
+ break;
+ }
+}
+/**
+ * Intel cpuid configuration. Reference: Publication 241618
+ * Processor Identification and CPUID Instruction
+ * Application node 485, Jan 2011
+ */
+static void cpuid_configIntel(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ CPU_INST *w) /* IN-OUT: Workspace */
+{
+ H_UINT regs[4];
+
+ if (w->maxFn >=0x0b) {
+ regs[ECX] = 0;
+ cpuid(0x0b,0,regs);
+ if (regs[EBX]!=0)
+ w->flags |= SRC_CPUID_LEAFB;
+ }
+#if 0
+ if (w->flags & SRC_CPUID_HT)
+ ;
+ else
+ ;
+#endif
+ if (w->maxFn >=4)
+ cpuid_configIntel4(anchor, w, regs);
+ if (w->maxFn >= 2)
+ cpuid_configIntel2(anchor, w, regs);
+}
+/**
+ * Configure caches using cpuid leaf 2. This is a legacy method that only determines
+ * level 1 cache. Still needed because trace cache is not reported elsewhere.
+ */
+static void cpuid_configIntel2(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ CPU_INST *w, /* IN-OUT: Workspace */
+ H_UINT *regs) /* IN-OUT: registers */
+{
+ /* L1 and Trace as per Intel application note 485, May 2012 */
+ static const H_UINT defs[] = {
+ 0x06, 'I', 8 , /* 4-way set assoc, 32 byte line size */
+ 0x08, 'I', 16 , /* 4-way set assoc, 32 byte line size */
+ 0x09, 'I', 32 , /* 4-way set assoc, 64 byte line size + */
+ 0x0a, 'D', 8 , /* 2 way set assoc, 32 byte line size */
+ 0x0c, 'D', 16 , /* 4-way set assoc, 32 byte line size */
+ 0x0d, 'D', 16 , /* 4-way set assoc, 64 byte line size + */
+ 0x0e, 'D', 24 , /* 6-way set assoc, 64 byte line size */
+ 0x10, 'D', 16 , /* 4-way set assoc, 64 byte line size */
+ 0x15, 'I', 16 , /* 4-way set assoc, 64 byte line size */
+ 0x2c, 'D', 32 , /* 8-way set assoc, 64 byte line size */
+ 0x30, 'I', 32 , /* 8-way set assoc, 64 byte line size */
+ 0x60, 'D', 16 , /* 8-way set assoc, sectored cache, 64 byte line size */
+ 0x66, 'D', 8 , /* 4-way set assoc, sectored cache, 64 byte line size */
+ 0x67, 'D', 16 , /* 4-way set assoc, sectored cache, 64 byte line size */
+ 0x68, 'D', 32 , /* 4-way set assoc, sectored cache, 64 byte line size */
+ 0x70, 'T', 12 , /* 8-way set assoc, trace cache */
+ 0x71, 'T', 16 , /* 8-way set assoc, trace cache */
+ 0x72, 'T', 32 , /* 8-way set assoc, trace cache */
+ 0x73, 'T', 64 , /* 8-way set assoc, trace cache */
+ 0x00, 0, 0 /* sentinel */
+ };
+ H_UINT i, j, n, m;
+
+ cpuid(0x02,0,regs);
+ n = regs[EAX]&0xff;
+ while(n--) {
+ for (i=0;i<4;i++) {
+ if (0==(regs[i] & 0x80000000)) {
+ while(0 != regs[i]) {
+ m = regs[i] & 0xff;
+ if (m==0xff)
+ w->flags |= SRC_CPUID_LEAF4;
+ else for (j=0;0 != defs[j];j += 3)
+ if (defs[j]==m) {
+ cfg_cacheAdd(anchor, SRC_CPUID_INTEL2, -1, 1, defs[j+1], defs[j+2]);
+ break;
+ }
+ regs[i]>>=8;
+ }
+ }
+ }
+ if (n) cpuid(0x02,0,regs);
+ }
+}
+/**
+ * Configure caches using cpuid leaf 4
+ */
+static void cpuid_configIntel4(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ CPU_INST *w, /* IN-OUT: Workspace */
+ H_UINT *regs) /* IN-OUT: registers */
+{
+ H_UINT level, type;
+ H_UINT i, j, lineSz, nParts, nWays, sz;
+
+ for(i=0;i<MAX_CACHES;i++) {
+ cpuid(0x04,i,regs);
+ if (0==i) {
+ H_UINT n = 1 + (regs[EAX]>>26);
+ for(j=0;j<n;j++)
+ cfg_bitSet(&w->cpuMap, j);
+ cfg_cpuAdd(anchor, SRC_CPUID_INTEL4, w);
+ }
+ switch(regs[EAX] & 31) {
+ case 0: type = 0 ; break;
+ case 1: type = 'D'; break;
+ case 2: type = 'I'; break;
+ case 3: type = 'U'; break;
+ default: type = '?'; break;
+ }
+ if (0==type) break;
+ regs[EAX] >>= 5;
+ level = (H_UINT)(regs[EAX] & 7);
+ lineSz = 1 + (regs[EBX] & 0xfff);
+ regs[EBX] >>= 12;
+ nParts = 1 + (regs[EBX] & 0x3ff);
+ regs[EBX] >>= 10;
+ nWays = 1 + regs[EBX];
+ sz = (nWays * nParts * lineSz * (regs[ECX]+1)) / 1024;
+ cfg_cacheAdd(anchor, SRC_CPUID_INTEL4, -1, level, type, sz);
+ }
+}
+#endif
+/************************* CPUID support ***************************************/
+/************************* VFS support ***************************************/
+#ifdef TUNING_VFS_ENABLE
+/**
+ * Get configuration
+ */
+static void vfs_config(
+ HOST_CFG *anchor) /* IN-OUT: result */
+{
+ char path[FILENAME_MAX];
+ CPU_INST inst;
+ H_UINT args[2];
+ int n;
+
+ args[0] = args[1] = 0;
+ snprintf(path, FILENAME_MAX, "%s/self/status", anchor->procfs);
+ if (-1 != vfs_configFile(anchor, path, vfs_configStatus))
+ args[0] |= SRC_VFS_STATUS;
+ snprintf(path, FILENAME_MAX, "%s/devices/system/cpu/online", anchor->sysfs);
+ if (-1 != vfs_configFile(anchor, path, vfs_configOnline))
+ args[0] |= SRC_VFS_ONLINE;
+ snprintf(path, FILENAME_MAX, "%s/cpuinfo", anchor->procfs);
+ if (-1 != vfs_configFile(anchor, path, vfs_configCpuInfo))
+ args[0] |= SRC_VFS_CPUINFO;
+ snprintf(path, FILENAME_MAX, "%s/devices/system/cpu", anchor->sysfs);
+ if (-1 != vfs_configDir(anchor, path, vfs_configCpuDir, args)) {
+ memset(&inst, 0, sizeof(CPU_INST));
+ args[0] |= SRC_VFS_CPUDIR;
+ for(n=-1;(n=cfg_bitNext(&anchor->pCpuInfo,n))!=-1;)
+ cfg_bitSet(&inst.cpuMap, n);
+ if (cfg_bitCount(&inst.cpuMap)>0)
+ cfg_cpuAdd(anchor, SRC_VFS_CPUINFO, &inst);
+ }
+ for(n=-1;(n=cfg_bitNext(&anchor->pCacheInfo,n))!=-1;) {
+ snprintf(path, FILENAME_MAX, "%s/devices/system/cpu/cpu%d/cache", anchor->sysfs, n);
+ args[1] = n;
+ vfs_configDir(anchor, path, vfs_configInfoCache, args);
+ }
+}
+/**
+ * Call back to get cpus and from cpu subdirectories
+ */
+static int vfs_configCpuDir(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ char *input, /* filename */
+ H_UINT *pArg) /* parameter */
+{
+
+ (void)pArg;
+ if (strlen(input)> 3) {
+ char term[32];
+ int cpu;
+
+ cpu = atoi(input+3);
+ (void)snprintf(term, 32, "cpu%d", cpu);
+ if (!strcmp(term, input))
+ cfg_bitSet(&anchor->pCacheInfo, cpu);
+ }
+ return 0;
+}
+/**
+ * Call back to get cpus from cpuinfo
+ */
+static int vfs_configCpuInfo(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ char *input) /* input text */
+{
+ char *s = strchr(input, ':');
+
+ if (NULL != s) {
+ char key[32], value[32];
+ *s++ = '\0';
+ if (1==sscanf(input, "%31s", key) && 1==sscanf(s, "%31s", value)) {
+ if (!strcmp("processor",key))
+ cfg_bitSet(&anchor->pCpuInfo, atoi(value));
+ }
+ }
+ return 0;
+}
+/**
+ * Process a configuration directory
+ */
+static int vfs_configDir(
+ HOST_CFG *pAnchor, /* IN-OUT: result */
+ char *path, /* IN: directory path */
+ pDirFilter filter, /* IN: entry filter */
+ H_UINT *pArg) /* IN: filter arg */
+{
+ DIR *d;
+ int rv=-1;
+
+ if (NULL != (d = opendir(path))) {
+ struct dirent *ent;
+
+ while (NULL!=(ent = readdir(d))) {
+ if (0!=(rv = (*filter)(pAnchor, ent->d_name, pArg)))
+ break;
+ }
+ (void)closedir(d);
+ }
+ return rv;
+}
+/**
+ * Process a configuration file
+ */
+static int vfs_configFile(
+ HOST_CFG *pAnchor, /* IN-OUT: result */
+ char *path, /* IN: file path */
+ pFilter filter) /* IN: input filter */
+{
+ FILE *f;
+ int rv=-1;
+
+ if (NULL != (f = fopen(path, "rb"))) {
+ char buf[VFS_LINESIZE];
+
+ while(fgets(buf, VFS_LINESIZE, f))
+ if (0!=(rv = (*filter)(pAnchor, buf)))
+ break;
+ fclose(f);
+ }
+ return rv;
+}
+/**
+ * Call back to get cache details
+ */
+static int vfs_configInfoCache(
+ HOST_CFG *pAnchor, /* IN-OUT: result */
+ char *input, /* IN: path name */
+ H_UINT *pArgs)
+{
+ if (strlen(input)> 5) {
+ char path[FILENAME_MAX];
+ int idx;
+
+ idx = atoi(input+5);
+ (void)snprintf(path, 32, "index%d", idx);
+ if (!strcmp(path, input)) {
+ int plen, ctype, level, size;
+
+ plen = snprintf(path, FILENAME_MAX, "%s/devices/system/cpu/cpu%d/cache/index%d/level",
+ pAnchor->sysfs, pArgs[1], idx) - 5;
+ level = vfs_configFile(pAnchor, path, vfs_configInt);
+ strcpy(path+plen, "type");
+ ctype = vfs_configFile(pAnchor, path, vfs_configType);
+ strcpy(path+plen, "size");
+ size = vfs_configFile(pAnchor, path, vfs_configInt);
+ if (size == -1)
+ size = ctype == 'I' ? GENERIC_ICACHE : GENERIC_DCACHE;
+ cfg_cacheAdd(pAnchor, SRC_VFS_INDEX, pArgs[1], level, ctype, size);
+ }
+ }
+ return 0;
+}
+/**
+ * Call back to get cpus from online file
+ */
+static int vfs_configOnline(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ char *input) /* IN: input text */
+{
+ vfs_parseList(&anchor->pOnline, input);
+ return 1;
+}
+/**
+ * Call back to return a single integer input
+ */
+static int vfs_configInt(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ char *input) /* IN: input text */
+{
+ (void)anchor;
+ return atoi(input);
+}
+/**
+ * Call back to get cpus and memory from status file
+ */
+static int vfs_configStatus(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ char *input) /* IN: input text */
+{
+ char *s = strchr(input, ':');
+
+ if (NULL != s) {
+ char key[32], value[VFS_LINESIZE-32];
+
+ *s++ = '\0';
+ if (1==sscanf(input, "%31s", key) && 1==sscanf(s, "%223s", value)) {
+ if (!strcmp("Cpus_allowed", key))
+ vfs_parseMask(&anchor->pAllowed, value);
+ else if (!strcmp("Mems_allowed", key))
+ vfs_parseMask(&anchor->mAllowed, value);
+ }
+ }
+ return 0;
+}
+/**
+ * Call back to return the first byte of input
+ */
+int vfs_configType(
+ HOST_CFG *anchor, /* IN-OUT: result */
+ char *input) /* IN: input text */
+{
+ (void) anchor;
+ return input[0];
+}
+/**
+* Parse the List format described in cpuset(7)
+*/
+static void vfs_parseList( /* RETURN: None */
+ TOPO_MAP *map, /* OUT: bit map */
+ char *input) /* IN: list text */
+{
+ char *term, c;
+ int bounds[2], n;
+
+ cfg_bitClear(map);
+ for(term = strtok(input, ",");term != NULL;term = strtok(NULL, ",")) {
+ n = bounds[0] = bounds[1] = 0;
+ while(0 != (int)(c = *term++))
+ switch(c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ bounds[n] = bounds[n] * 10 + (int)(c - '0');
+ break;
+ case '-':
+ n = 1;
+ }
+ cfg_bitSet(map, bounds[0]);
+ if (0 != n)
+ while(++bounds[0] <= bounds[1])
+ cfg_bitSet(map, bounds[0]);
+ }
+}
+/**
+ * Parse the Mask format described in cpuset(7)
+ */
+static void vfs_parseMask( /* RETURN: None */
+ TOPO_MAP *map, /* OUT: bit map */
+ char *input) /* IN: list text */
+{
+ char *term, c;
+ int m, n;
+
+ cfg_bitClear(map);
+ for(term = strtok(input, ",");term != NULL;term = strtok(NULL, ",")) {
+ m = 0;
+ while(0 != (int)(c = *term++))
+ switch(c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ m = m * 16 + (int)(c - '0');
+ break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ m = m * 16 + (int)(c - 'A') + 10;
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ m = m * 16 + (int)(c - 'a') + 10;
+ }
+ for(n=map->msw;n>=0;n--)
+ map->bits[n+1] = map->bits[n];
+ if (0 != map->bits[map->msw+1])
+ map->msw++;
+ map->bits[0] = 0;
+ for(n=0;n<32;n++)
+ if (m & (1<<n))
+ cfg_bitSet(map, n);
+ }
+}
+#endif
+
+/************************* VFS support ***************************************/
+
diff --git a/src/havegetune.h b/src/havegetune.h
new file mode 100644
index 0000000..5283a0b
--- /dev/null
+++ b/src/havegetune.h
@@ -0,0 +1,121 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HAVEGETUNE_H
+#define HAVEGETUNE_H
+
+#include "havegecollect.h"
+/**
+ * Some systems supply a maximum
+ */
+#ifndef FILENAME_MAX
+#define FILENAME_MAX 256 /* Max path length */
+#endif
+/**
+ * Limits
+ */
+#define MAX_BIT_IDX (256/BITS_PER_H_UINT) /* Size of resource bitmaps */
+#define MAX_CACHES 8 /* Max cache types */
+#define MAX_CPUS 8 /* Max cpu types */
+/**
+ * Object used to represent a set of objects
+ */
+typedef struct {
+ H_UINT bits[MAX_BIT_IDX];
+ int msw;
+ H_UINT source;
+} TOPO_MAP;
+/**
+ * Cache instance
+ */
+typedef struct {
+ TOPO_MAP cpuMap; /* what cpus have this cache */
+ H_UINT type; /* 'I'nstruction, 'D'ata, 'U'nified, 'T'race */
+ H_UINT level; /* 0-15................ */
+ H_UINT size; /* size in KB */
+} CACHE_INST;
+/**
+ * Sources for CACHE_INST TOPO_MAP
+ */
+#define SRC_DEFAULT 0x00001
+#define SRC_PARAM 0x00002
+#define SRC_CPUID_AMD6 0x00004
+#define SRC_CPUID_AMD5 0x00008
+#define SRC_CPUID_INTEL2 0x00010
+#define SRC_CPUID_INTEL4 0x00020
+#define SRC_VFS_INDEX 0x00040
+/**
+ * CPU instance
+ */
+typedef struct {
+ TOPO_MAP cpuMap; /* what cpus have this config */
+ H_UINT signature; /* processor signature */
+ H_UINT flags;
+ H_UINT maxFn;
+ H_UINT maxFnx;
+ char vendor[16];
+} CPU_INST;
+/**
+ * Sources for CPU_INST TOPO_MAP
+ */
+#define SRC_CPUID_PRESENT 0x00100
+#define SRC_CPUID_HT 0x00200
+#define SRC_CPUID_AMD 0x00400
+#define SRC_CPUID_AMD8 0x00800
+#define SRC_CPUID_LEAFB 0x01000
+#define SRC_CPUID_LEAF4 0x02000
+#define SRC_VFS_STATUS 0x04000
+#define SRC_VFS_ONLINE 0x08000
+#define SRC_VFS_CPUINFO 0x10000
+#define SRC_VFS_CPUDIR 0x20000
+/**
+ * Size of representation fields
+ */
+#define SZ_BUILDREP 32
+#define SZ_CPUREP 64
+#define SZ_CACHEREP 32
+/**
+ * The result of tuning
+ */
+typedef struct {
+ char *procfs; /* where proc is mounted */
+ char *sysfs; /* where sys is mounted */
+ char buildOpts[SZ_BUILDREP]; /* build options */
+ char cpuOpts[SZ_CPUREP]; /* cpu options */
+ char icacheOpts[SZ_CACHEREP]; /* icache options */
+ char dcacheOpts[SZ_CACHEREP]; /* dcache options */
+ TOPO_MAP pAllowed; /* allowed processors */
+ TOPO_MAP pOnline; /* processors online */
+ TOPO_MAP pCpuInfo; /* processors with info */
+ TOPO_MAP pCacheInfo; /* processors with cache info */
+ TOPO_MAP mAllowed; /* allowed memory */
+ H_UINT a_cpu; /* suggested cpu */
+ H_UINT i_tune; /* suggested i cache value */
+ H_UINT d_tune; /* suggested d cache value */
+ int ctCpu; /* number of cpu types */
+ int ctCache; /* number of cache items */
+ CPU_INST cpus[MAX_CPUS]; /* cpu instances */
+ CACHE_INST caches[MAX_CACHES+2]; /* cache instances */
+} HOST_CFG;
+/**
+ * Tuning interface
+ */
+void havege_tune(HOST_CFG *env, H_PARAMS *params);
+
+#endif
diff --git a/src/oneiteration.h b/src/oneiteration.h
new file mode 100644
index 0000000..e6b16d8
--- /dev/null
+++ b/src/oneiteration.h
@@ -0,0 +1,201 @@
+/**
+ ** Simple entropy harvester based upon the havege RNG
+ **
+ ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com
+ ** Copyright 2009-2013 Gary Wuertz gary@issiweb.com
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **
+ ** This source is an adaptation of work released as
+ **
+ ** Copyright (C) 2006 - André Seznec - Olivier Rochecouste
+ **
+ ** under version 2.1 of the GNU Lesser General Public License
+ **
+ ** The original form is retained with minor variable renames for
+ ** more consistent macro itilization. See havegecollect.c for
+ ** details.
+ */
+
+/* ------------------------------------------------------------------------
+ * On average, one iteration accesses two 8-word blocks in the PWALK
+ * table, and generates 16 words in the RESULT array.
+ *
+ * The data read in the Walk table are updated and permuted after each use.
+ * The result of the hardware clock counter read is used for this update.
+ *
+ * 21 conditional tests are present. The conditional tests are grouped in
+ * two nested groups of 10 conditional tests and 1 test that controls the
+ * permutation.
+ *
+ * In average, there should be 4 tests executed and, in average, 2 of them
+ * should be mispredicted.
+ * ------------------------------------------------------------------------
+ */
+
+ PTTEST = PT >> 20;
+
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ PTTEST = PTTEST >> 1;
+ pt = (PT >> 18) & 7;
+
+ PT = PT & ANDPT;
+
+ HARDCLOCKR(HTICK1);
+
+ Pt0 = &PWALK[PT];
+ Pt1 = &PWALK[PT2];
+ Pt2 = &PWALK[PT ^ 1];
+ Pt3 = &PWALK[PT2 ^ 4];
+
+ RESULT[i++] ^= *Pt0;
+ RESULT[i++] ^= *Pt1;
+ RESULT[i++] ^= *Pt2;
+ RESULT[i++] ^= *Pt3;
+
+ inter = ROR32(*Pt0,1) ^ HTICK1;
+ *Pt0 = ROR32(*Pt1,2) ^ HTICK1;
+ *Pt1 = inter;
+ *Pt2 = ROR32(*Pt2, 3) ^ HTICK1;
+ *Pt3 = ROR32(*Pt3, 4) ^ HTICK1;
+
+ Pt0 = &PWALK[PT ^ 2];
+ Pt1 = &PWALK[PT2 ^ 2];
+ Pt2 = &PWALK[PT ^ 3];
+ Pt3 = &PWALK[PT2 ^ 6];
+
+ RESULT[i++] ^= *Pt0;
+ RESULT[i++] ^= *Pt1;
+ RESULT[i++] ^= *Pt2;
+ RESULT[i++] ^= *Pt3;
+
+ if (PTTEST & 1) {
+ Ptinter = Pt0;
+ Pt2 = Pt0;
+ Pt0 = Ptinter;
+ }
+
+ PTTEST = (PT2 >> 18);
+ inter = ROR32(*Pt0, 5) ^ HTICK1;
+ *Pt0 = ROR32(*Pt1, 6) ^ HTICK1;
+ *Pt1 = inter;
+
+ HARDCLOCKR(HTICK2);
+
+ *Pt2 = ROR32(*Pt2, 7) ^ HTICK2;
+ *Pt3 = ROR32(*Pt3, 8) ^ HTICK2;
+
+ Pt0 = &PWALK[PT ^ 4];
+ Pt1 = &PWALK[PT2 ^ 1];
+
+ PT2 = (RESULT[(i - 8) ^ PT1] ^ PWALK[PT2 ^ PT1 ^ 7]);
+ PT2 = ((PT2 & ANDPT) & (0xfffffff7)) ^ ((PT ^ 8) & 0x8);
+
+ /* avoid PT and PT2 to point on the same cache block */
+ PT1 = ((PT2 >> 28) & 7);
+
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ if (PTTEST & 1) {
+ PTTEST ^= 3; PTTEST = PTTEST >> 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ Pt2 = &PWALK[PT ^ 5];
+ Pt3 = &PWALK[PT2 ^ 5];
+
+ RESULT[i++] ^= *Pt0;
+ RESULT[i++] ^= *Pt1;
+ RESULT[i++] ^= *Pt2;
+ RESULT[i++] ^= *Pt3;
+
+ inter = ROR32(*Pt0 , 9) ^ HTICK2;
+ *Pt0 = ROR32(*Pt1 , 10) ^ HTICK2;
+ *Pt1 = inter;
+ *Pt2 = ROR32(*Pt2, 11) ^ HTICK2;
+ *Pt3 = ROR32(*Pt3, 12) ^ HTICK2;
+
+ Pt0 = &PWALK[PT ^ 6];
+ Pt1 = &PWALK[PT2 ^ 3];
+ Pt2 = &PWALK[PT ^ 7];
+ Pt3 = &PWALK[PT2 ^ 7];
+
+ RESULT[i++] ^= *Pt0;
+ RESULT[i++] ^= *Pt1;
+ RESULT[i++] ^= *Pt2;
+ RESULT[i++] ^= *Pt3;
+
+ inter = ROR32(*Pt0, 13) ^ HTICK2;
+ *Pt0 = ROR32(*Pt1, 14) ^ HTICK2;
+ *Pt1 = inter;
+ *Pt2 = ROR32(*Pt2, 15) ^ HTICK2;
+ *Pt3 = ROR32(*Pt3, 16) ^ HTICK2;
+
+ /* avoid PT and PT2 to point on the same cache block */
+ PT = (((RESULT[(i - 8) ^ pt] ^ PWALK[PT ^ pt ^ 7])) &
+ (0xffffffef)) ^ ((PT2 ^ 0x10) & 0x10);