diff options
author | Daniel Baumann <daniel@debian.org> | 2024-11-10 15:31:03 +0100 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-11-10 15:31:03 +0100 |
commit | 2b16d0d8a6bead5bcc2125b890bf1a13d19602dc (patch) | |
tree | b67952daab2d78e87c103ed10ece33ad6a9a2167 /src/havegecollect.c | |
parent | Initial commit. (diff) | |
download | haveged-2b16d0d8a6bead5bcc2125b890bf1a13d19602dc.tar.xz haveged-2b16d0d8a6bead5bcc2125b890bf1a13d19602dc.zip |
Adding upstream version 1.9.14.upstream/1.9.14
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'src/havegecollect.c')
-rw-r--r-- | src/havegecollect.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/src/havegecollect.c b/src/havegecollect.c new file mode 100644 index 0000000..1c82e51 --- /dev/null +++ b/src/havegecollect.c @@ -0,0 +1,480 @@ +/** + ** Simple entropy harvester based upon the havege RNG + ** + ** Copyright 2018-2021 Jirka Hladky hladky DOT jiri AT gmail DOT com + ** Copyright 2009-2014 Gary Wuertz gary@issiweb.com + ** Copyright 2011-2012 BenEleventh Consulting manolson@beneleventh.com + ** + ** This program is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/** + * This compile unit isolates the operation of the HAVEGE algorithm to better + * deal with compiler issues. Extensive macro expansion used to deal with + * hardware variations. + */ +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "havegecollect.h" +#include "havegetest.h" +#include "havegetune.h" +/** + * Injection and capture diagnostics + */ +#if defined(RAW_IN_ENABLE) || defined(RAW_OUT_ENABLE) +#define DIAGNOSTICS_ENABLE +#endif +/** + * Option to use clockgettime() as timer source + */ +#if defined(ENABLE_CLOCK_GETTIME) +#include <time.h> + +#undef HARDCLOCK +#define HARDCLOCK(x) x = havege_clock() +/** + * Provide a generic timer fallback + */ +static H_UINT havege_clock(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return (H_UINT)(ts.tv_nsec + ts.tv_sec * 1000000000LL); +} +#endif + +/** + * Memory allocation sizing + */ +#define SZH_INIT sizeof(H_COLLECT)+sizeof(char *)*(LOOP_CT + 2) +#define SZH_COLLECT(a) sizeof(H_COLLECT)+sizeof(H_UINT)*(a+16384-1) +/** + * The HAVEGE collector is created by interleaving instructions generated by + * oneiteration.h with the LOOP() output to control the sequence. At each + * LOOP() point, the following actions are possible. + */ +typedef enum { + LOOP_NEXT, /* Next loop */ + LOOP_ENTER, /* First loop */ + LOOP_EXIT /* Last loop */ +} LOOP_BRANCH; +/** + * The LOOP macro labels calculation sequences generated by oneiteration.h in + * decreasing order from LOOPCT down to 0. During a normal collection, the + * loop construct only introduces an extra conditional branch into the instruction + * stream. For the exceptional conditions (initialization, end-of-loop, and + * raw HARDCLOCK capture), the return from havege_cp() is used to determine + * the action to be taken. + */ +#define LOOP(n,m) loop##n: if (n < h_ctxt->havege_cdidx) { \ + switch(havege_cp(h_ctxt,i,n,LOOP_PT(n))) { \ + case LOOP_NEXT: goto loop##m; \ + case LOOP_ENTER: goto loop_enter; \ + case LOOP_EXIT: goto loop_exit; \ + } \ + } +/** + * These macros below bind the code contained in oneiteration.h to the H_COLLECT + * instance defined above + */ +#define ANDPT (h_ctxt->havege_andpt) +#define PTTEST (h_ctxt->havege_PTtest) +#define PT (h_ctxt->havege_PT) +#define PT1 (h_ctxt->havege_pt2) +#define PT2 (h_ctxt->havege_PT2) +#define PWALK (h_ctxt->havege_pwalk) +#define RESULT (h_ctxt->havege_bigarray) +/** + * Previous diagnostic support has been replaced. The new implementation provides + * simultaneous access to both the noise source (i.e. the timer tics) and the + * output. The tics buffer is also used by the injection diagnostic if enabled + */ +#ifdef DIAGNOSTICS_ENABLE +#define HTICK1 (h_ctxt->havege_tics[i>>3]) +#define HTICK2 (h_ctxt->havege_tics[i>>3]) +#define SZ_TICK ((h_ptr->i_collectSz)>>3) +#else +#define HTICK1 (h_ctxt->havege_tic) +#define HTICK2 (h_ctxt->havege_tic) +#define SZ_TICK 0 +#endif + +/** + * If the injection diagnostic is enabled, use a wrapper for the timer source + */ +#ifdef RAW_IN_ENABLE +static H_UINT havege_inject(H_COLLECT *h_ctxt, H_UINT x); + +#define HARDCLOCKR(x) x=havege_inject(h_ctxt, x) +#else +#define HARDCLOCKR(x) HARDCLOCK(x) +#endif +/** + * inline optimization - left conditional for legacy systems + */ +#if 0 +#define ROR32(value,shift) ((value >> (shift)) | (value << (32-shift))) +#else +inline static H_UINT ror32(const H_UINT value, const H_UINT shift) { + return (value >> shift) | (value << (32 - shift)); +} +#define ROR32(value,shift) ror32(value, shift) +#endif +/** + * Local prototypes + */ +static LOOP_BRANCH havege_cp(H_COLLECT *h_ctxt, H_UINT i, H_UINT n, char *p); +/** + * Protect the collection mechanism against ever-increasing gcc optimization + */ +#if defined (GCC_VERSION) && GCC_VERSION >= 40400 +static int havege_gather(H_COLLECT * h_ctxt) __attribute__((optimize(1))); +#else +static int havege_gather(H_COLLECT * h_ctxt); +#endif +static void havege_ndinit(H_PTR h_ptr, struct h_collect *h_ctxt); + +/** + * Create a collector + */ +H_COLLECT *havege_ndcreate(/* RETURN: NULL on failure */ + H_PTR h_ptr, /* IN-OUT: application instance */ + H_UINT nCollector) /* IN: The collector instance */ +{ + H_UINT i,offs,*p,d_cache; + H_UINT szBuffer; + H_COLLECT *h_ctxt; + + szBuffer = h_ptr->i_collectSz; + d_cache = ((CACHE_INST *)(h_ptr->dataCache))->size; + h_ctxt = (H_COLLECT *) calloc(SZH_COLLECT(szBuffer + SZ_TICK),1); + if (NULL != h_ctxt) { + h_ctxt->havege_app = h_ptr; + h_ctxt->havege_idx = nCollector; + h_ctxt->havege_raw = h_ptr->havege_opts & 0xff00; + h_ctxt->havege_rawInput = h_ptr->inject; + h_ctxt->havege_szCollect = szBuffer; + h_ctxt->havege_szFill = szBuffer>>3; + h_ctxt->havege_cdidx = h_ptr->i_idx; + p = (H_UINT *) RESULT; + h_ctxt->havege_err = H_NOERR; + h_ctxt->havege_tests = 0; + h_ctxt->havege_extra = 0; + h_ctxt->havege_tics = p+szBuffer; + + /** An intermediate walk table twice the size of the L1 cache is allocated + ** for use in permuting time stamp readings. The is meant to exercise + ** processor TLBs. + */ + ANDPT = ((2*d_cache*1024)/sizeof(H_UINT))-1; + p = (H_UINT *) calloc((ANDPT + 4097)*sizeof(H_UINT),1); + if (NULL != p) { + h_ctxt->havege_extra = p; + offs = (H_UINT)((((unsigned long)&p[4096])&0xfff)/sizeof(H_UINT)); + PWALK = &p[4096-offs]; + /** + * Warm up the generator, running the startup tests + */ +#if defined(RAW_IN_ENABLE) + if (0 == (h_ctxt->havege_raw & H_DEBUG_TEST_IN)) +#endif + { + H_UINT t0=0; + + (void)havege_gather(h_ctxt); /* first sample */ + t0 = HTICK1; + for(i=1;i<MININITRAND;i++) + (void)havege_gather(h_ctxt); /* warmup rng */ + if (HTICK1==t0) { /* timer stuck? */ + h_ptr->error = H_NOTIMER; + havege_nddestroy(h_ctxt); + return NULL; + } + } +#ifdef ONLINE_TESTS_ENABLE + { + procShared *ps = (procShared *)(h_ptr->testData); + while(0!=ps->run(h_ctxt, 0)) { /* run tot tests */ + (void)havege_gather(h_ctxt); + } + } + if (H_NOERR != (h_ptr->error = h_ctxt->havege_err)) { + havege_nddestroy(h_ctxt); + return NULL; + } +#endif + h_ctxt->havege_nptr = szBuffer; + if (0 == (h_ctxt->havege_raw & H_DEBUG_RAW_OUT)) + h_ctxt->havege_szFill = szBuffer; + } + else { + havege_nddestroy(h_ctxt); + h_ptr->error = H_NOWALK; + return NULL; + } + } + else h_ptr->error = H_NOCOLLECT; + return h_ctxt; +} +/** + * Destruct a collector + */ +void havege_nddestroy( /* RETURN: none */ + H_COLLECT *h_ctxt) /* IN: collector context */ +{ + if (0 != h_ctxt) { + if (h_ctxt->havege_extra!=0) { + free(h_ctxt->havege_extra); + h_ctxt->havege_extra = 0; + } + if (h_ctxt->havege_tests!=0) { + free(h_ctxt->havege_tests); + h_ctxt->havege_tests = 0; + } + free((void *)h_ctxt); + } +} +/** + * Read from the collector. + */ +H_UINT havege_ndread( /* RETURN: data value */ + H_COLLECT *h_ctxt) /* IN: collector context */ +{ + if (h_ctxt->havege_nptr >= h_ctxt->havege_szFill) { + H_PTR h_ptr = (H_PTR)(h_ctxt->havege_app); + pMeter pm; + + if (0 != (pm = h_ptr->metering)) + (*pm)(h_ctxt->havege_idx, 0); +#ifdef ONLINE_TESTS_ENABLE + { + procShared *ps = (procShared *)(h_ptr->testData); + do { + (void) havege_gather(h_ctxt); + (void) ps->run(h_ctxt, 1); + } while(ps->discard(h_ctxt)>0); + } +#else + (void) havege_gather(h_ctxt); +#endif + h_ptr->n_fills += 1; + if (0 != pm) + (*pm)(h_ctxt->havege_idx, 1); + h_ctxt->havege_nptr = 0; + } +#ifdef RAW_OUT_ENABLE + if (0!=(h_ctxt->havege_raw & H_DEBUG_RAW_OUT)) + return h_ctxt->havege_tics[h_ctxt->havege_nptr++]; +#endif + return RESULT[h_ctxt->havege_nptr++]; +} +/** + * Setup haveged + */ +void havege_ndsetup( /* RETURN: None */ + H_PTR h_ptr) /* IN-OUT: application instance */ +{ + char wkspc[SZH_INIT]; + + memset(wkspc, 0, SZH_INIT); + havege_ndinit(h_ptr, (struct h_collect *) wkspc); +} +/** + * This method is called only for control points NOT part of a normal collection: + * + * a) For a collection loop after all iterations are performed, this function + * determines if the collection buffer is full. + * b) For initialization, this method saves the address of the collection point + * for analysis at the end of the loop. + */ +static LOOP_BRANCH havege_cp( /* RETURN: branch to take */ + H_COLLECT *h_ctxt, /* IN: collection context */ + H_UINT i, /* IN: collection offset */ + H_UINT n, /* IN: iteration index */ + char *p) /* IN: code pointer */ +{ + + if (h_ctxt->havege_cdidx <= LOOP_CT) + return i < h_ctxt->havege_szCollect? LOOP_ENTER : LOOP_EXIT; + ((char **)RESULT)[n] = CODE_PT(p); + if (n==0) h_ctxt->havege_cdidx = 0; + return LOOP_NEXT; +} + +/** + * The collection loop is constructed by repetitions of oneinteration.h interleaved + * with control points generated by the LOOP macro. + */ +static int havege_gather( /* RETURN: 1 if initialized */ + H_COLLECT * h_ctxt) /* IN: collector context */ +{ + H_UINT i=0,pt=0,inter=0; + H_UINT *Pt0, *Pt1, *Pt2, *Pt3, *Ptinter; + +#if defined(RAW_IN_ENABLE) +if (0 != (h_ctxt->havege_raw & H_DEBUG_RAW_IN)) { + (*h_ctxt->havege_rawInput)(h_ctxt->havege_tics, h_ctxt->havege_szCollect>>3); + h_ctxt->havege_tic = h_ctxt->havege_tics[0]; + } +else if (0 != (h_ctxt->havege_raw & H_DEBUG_TEST_IN)) { + (*h_ctxt->havege_rawInput)(RESULT, h_ctxt->havege_szCollect); + return 1; + } +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + +loop_enter: +LOOP(40,39) + #include "oneiteration.h" +LOOP(39,38) + #include "oneiteration.h" +LOOP(38,37) + #include "oneiteration.h" +LOOP(37,36) + #include "oneiteration.h" +LOOP(36,35) + #include "oneiteration.h" +LOOP(35,34) + #include "oneiteration.h" +LOOP(34,33) + #include "oneiteration.h" +LOOP(33,32) + #include "oneiteration.h" +LOOP(32,31) + #include "oneiteration.h" +LOOP(31,30) + #include "oneiteration.h" +LOOP(30,29) + #include "oneiteration.h" +LOOP(29,28) + #include "oneiteration.h" +LOOP(28,27) + #include "oneiteration.h" +LOOP(27,26) + #include "oneiteration.h" +LOOP(26,25) + #include "oneiteration.h" +LOOP(25,24) + #include "oneiteration.h" +LOOP(24,23) + #include "oneiteration.h" +LOOP(23,22) + #include "oneiteration.h" +LOOP(22,21) + #include "oneiteration.h" +LOOP(21,20) + #include "oneiteration.h" +LOOP(20,19) + #include "oneiteration.h" +LOOP(19,18) + #include "oneiteration.h" +LOOP(18,17) + #include "oneiteration.h" +LOOP(17,16) + #include "oneiteration.h" +LOOP(16,15) + #include "oneiteration.h" +LOOP(15,14) + #include "oneiteration.h" +LOOP(14,13) + #include "oneiteration.h" +LOOP(13,12) + #include "oneiteration.h" +LOOP(12,11) + #include "oneiteration.h" +LOOP(11,10) + #include "oneiteration.h" +LOOP(10,9) + #include "oneiteration.h" +LOOP(9,8) + #include "oneiteration.h" +LOOP(8,7) + #include "oneiteration.h" +LOOP(7,6) + #include "oneiteration.h" +LOOP(6,5) + #include "oneiteration.h" +LOOP(5,4) + #include "oneiteration.h" +LOOP(4,3) + #include "oneiteration.h" +LOOP(3,2) + #include "oneiteration.h" +LOOP(2,1) + #include "oneiteration.h" +LOOP(1,0) + #include "oneiteration.h" +LOOP(0,0) + (void)havege_cp(h_ctxt, i,0,LOOP_PT(0)); +#pragma GCC diagnostic pop + +loop_exit: + return ANDPT==0? 0 : 1; +} +#ifdef RAW_IN_ENABLE +/** + * Wrapper for noise injector. When input is injected, the hardclock + * call is not made and the contents of the tic buffer are used + * unchanged from when the inject call was made at the top of the + * loop. + */ +static H_UINT havege_inject( /* RETURN: clock value */ + H_COLLECT *h_ctxt, /* IN: workspace */ + H_UINT x) /* IN: injected value */ +{ + if (0==(h_ctxt->havege_raw & H_DEBUG_RAW_IN)) { + HARDCLOCK(x); + } + return x; +} +#endif +/** + * Initialize the collection loop + */ +#if defined (GCC_VERSION) && GCC_VERSION >= 40600 +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif + +static void havege_ndinit( /* RETURN: None */ + H_PTR h_ptr, /* IN-OUT: application instance */ + struct h_collect *h_ctxt) /* IN: workspace */ +{ + char **addr = (char **)(&RESULT[0]); + H_UINT sz; + int i; + + h_ctxt->havege_cdidx = LOOP_CT + 1; + (void)havege_gather(h_ctxt); + for (i=0;i<=LOOP_CT;i++) { + if (0 != (h_ptr->havege_opts & H_DEBUG_COMPILE)) { + h_ptr->print_msg("Address %u=%p\n", i, addr[i]); + } + RESULT[i] = labs(addr[i] - addr[LOOP_CT]); + if (i > 0 && 0 != (h_ptr->havege_opts & H_DEBUG_LOOP)) { + h_ptr->print_msg("Loop %u: offset=%u, delta=%u\n", i,RESULT[i],RESULT[i-1]-RESULT[i]); + } + } + h_ptr->i_maxidx = LOOP_CT; + h_ptr->i_maxsz = RESULT[1]; + sz = ((CACHE_INST *)(h_ptr->instCache))->size * 1024; + for(i=LOOP_CT;i>0;i--) + if (RESULT[i]>sz) + break; + h_ptr->i_idx = ++i; + h_ptr->i_sz = RESULT[i]; +} |