1
0
Fork 0

Adding upstream version 1.9.14.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-05 13:10:21 +01:00
parent ddf4b25f8f
commit 49fcf7364a
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
88 changed files with 62468 additions and 0 deletions

34
src/Makefile.am Normal file
View file

@ -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

794
src/Makefile.in Normal file
View file

@ -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:

181
src/cpuid-43.h Normal file
View file

@ -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;
}

785
src/havege.c Normal file
View file

@ -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

308
src/havege.h Normal file
View file

@ -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

460
src/havegecmd.c Normal file
View file

@ -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

103
src/havegecmd.h Normal file
View file

@ -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

480
src/havegecollect.c Normal file
View file

@ -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];
}

215
src/havegecollect.h Normal file
View file

@ -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

1008
src/haveged.c Normal file

File diff suppressed because it is too large Load diff

100
src/haveged.h Normal file
View file

@ -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

1030
src/havegetest.c Normal file

File diff suppressed because it is too large Load diff

225
src/havegetest.h Normal file
View file

@ -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

926
src/havegetune.c Normal file
View file

@ -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 ***************************************/

121
src/havegetune.h Normal file
View file

@ -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

201
src/oneiteration.h Normal file
View file

@ -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);