/haveged-1.4/src/havegecollect.c
C | 420 lines | 294 code | 14 blank | 112 comment | 43 complexity | 781ae29e75a4c681b10201c105bf2cc7 MD5 | raw file
Possible License(s): GPL-3.0
- /**
- ** Simple entropy harvester based upon the havege RNG
- **
- ** Copyright 2009-2012 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. Portability of the algorithm is improved by
- * isolating environmental dependencies in the HARDCLOCK and CSZ macros.
- */
- #include "config.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "havege.h"
- #include "havegecollect.h"
- #define SZH_INIT sizeof(H_COLLECT)+sizeof(char *)*(LOOP_CT + 2)
- #define SZH_COLLECT(a) sizeof(H_COLLECT)+sizeof(U_INT)*(a+16384-1)
- /**
- * These macros below bind the code contained in oneiteration.h to the H_COLLECT
- * instance defined above
- */
- #define ANDPT (h_ctxt->havege_andpt)
- #define HTICK1 (h_ctxt->havege_hardtick1)
- #define HTICK2 (h_ctxt->havege_hardtick2)
- #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)
- /**
- * 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_THIS /* This 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; \
- case LOOP_THIS: break; \
- } \
- }
- /**
- * RAW mode is a diagnostic mode that gives access to HARDCLOCK() inputs. In RAW
- * mode havege_cp() is called at every control point. Raw modes must be enabled
- * be defining the corresponding symbols RAW_IN_ENABLE, RAW_OUT_ENABLE. Both
- * functions reuse portions of the collection buffer and cause havege_cp() to
- * be called on each and every control point and thus should not be enabled
- * in any production build.
- *
- * In order to use RAW_IN, a rawInput callback must be provided in NPRNG_INST
- * and DEBUG_RAW_IN must be passed as an input option. RAW_IN_ENABLE replaces
- * HARDCLOCKR() with code to select an input source based upon the DEBUG_RAW_IN
- * option. This changes the nature of the collection loop and should only be
- * enabled only during development.
- *
- * RAW_OUT does not modify the collection loop however, since RAW data is
- * 8 times more dense that normal output, nd_read() compensates for this
- * compression to deliver the requested output range.
- */
- #define RAW_SHIFT 3 /* RAW compression factor */
- /**
- * Derived constants for RAW mode
- */
- #define DEBUG_RAW (DEBUG_RAW_IN|DEBUG_RAW_OUT)
- #define RAW_RANGE (h_ctxt->havege_szCollect >> RAW_SHIFT)
- #define RAW_INJECT (h_ctxt->havege_szCollect - RAW_RANGE)
- #ifdef RAW_IN_ENABLE
- #undef RAW_IN_ENABLE
- #define RAW_IN_ENABLE DEBUG_RAW_IN
- #define HARDCLOCKR(x) if (0==(h_ctxt->havege_raw & DEBUG_RAW_IN)){HARDCLOCK(x);}
- #else
- #define RAW_IN_ENABLE 0
- #define HARDCLOCKR(x) HARDCLOCK(x)
- #endif
- #ifdef RAW_OUT_ENABLE
- #undef RAW_OUT_ENABLE
- #define RAW_OUT_ENABLE DEBUG_RAW_OUT
- #else
- #define RAW_OUT_ENABLE 0
- #endif
- /**
- * Wrapper for inline optimization
- */
- #if 0
- #define ROR32(value,shift) ((value >> (shift)) | (value << (32-shift)))
- #else
- inline U_INT ror32(const U_INT value, const U_INT 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, U_INT i, U_INT 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 */
- U_INT nCollector) /* IN: The collector instance */
- {
- U_INT i,offs,*p,d_cache;
- U_INT szBuffer, t0;
- H_COLLECT *h_ctxt;
- szBuffer = h_ptr->i_collectSz;
- d_cache = h_ptr->dataCache->size;
- h_ctxt = (H_COLLECT *) malloc(SZH_COLLECT(szBuffer));
- if (NULL != h_ctxt) {
- h_ctxt->havege_app = h_ptr;
- h_ctxt->havege_idx = nCollector;
- h_ctxt->havege_raw = 0;
- h_ctxt->havege_rawInput = h_ptr->params->injection;
- h_ctxt->havege_meter = h_ptr->params->metering;
- h_ctxt->havege_szCollect = h_ctxt->havege_szFill = szBuffer;
- h_ctxt->havege_cdidx = h_ptr->i_idx;
- /** 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(int))-1;
- p = (U_INT *) malloc((ANDPT + 4097)*sizeof(int));
- if (NULL != p) {
- offs = (U_INT)((((unsigned long)&p[4096])&0xfff)/sizeof(int));
- PWALK = &p[4096-offs];
- /**
- * Run a short timer sanity test while warming up the generator.
- */
- (void)havege_gather(h_ctxt);
- t0 = HTICK2;
- for(i=1;i<MININITRAND;i++) {
- (void)havege_gather(h_ctxt);
- if (HTICK1==HTICK2 && HTICK2==t0) {
- h_ptr->error = H_NOTIMER;
- return NULL;
- }
- t0 = HTICK2;
- }
- h_ctxt->havege_nptr = h_ctxt->havege_szCollect;
- if (0 != (h_ptr->havege_opts & DEBUG_RAW)) {
- h_ctxt->havege_raw = h_ctxt->havege_cdidx | (h_ptr->havege_opts & DEBUG_RAW) ;
- if (0 != (h_ctxt->havege_raw & DEBUG_RAW_OUT))
- h_ctxt->havege_szFill = RAW_RANGE;
- h_ctxt->havege_cdidx = LOOP_CT + 1;
- }
- }
- else {
- h_ptr->error = H_NOWALK;
- return NULL;
- }
- }
- h_ptr->error = H_NOCOLLECT;
- return h_ctxt;
- }
- /**
- * Read from the collector. For the RAW_OUT, additional collection cycles are run
- * in order to fill the buffer.
- */
- U_INT havege_ndread( /* RETURN: data value */
- H_COLLECT *h_ctxt) /* IN: collector context */
- {
- if (h_ctxt->havege_nptr >= h_ctxt->havege_szFill) {
- if (NULL != h_ctxt->havege_rawInput)
- (*h_ctxt->havege_rawInput)(RESULT + RAW_INJECT, RAW_RANGE);
- if (NULL != h_ctxt->havege_meter)
- (*h_ctxt->havege_meter)(h_ctxt->havege_idx, 0);
- (void) havege_gather(h_ctxt);
- if (NULL != h_ctxt->havege_meter)
- (*h_ctxt->havege_meter)(h_ctxt->havege_idx, 1);
- h_ctxt->havege_nptr = 0;
- }
- 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);
- }
- #ifdef HAVE_ISA_GENERIC
- #include <time.h>
- /**
- * Provide a timer fallback
- */
- static U_INT havege_clock(void)
- {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return (U_INT)(ts.tv_nsec + ts.tv_sec * 1000000000LL);
- }
- #endif
- /**
- * 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. This applies to both RAW
- * and normal collections.
- * b) For initialization, this method saves the address of the collection point
- * for analysis at the end of the loop.
- * c) For RAW_IN model control points which would be part of a normal collection,
- * hardtick variables for the NEXT interaction are loaded from the prepared data.
- * d) For RAW_OUT mode control points which would be part of a normal collection,
- * hardtick variables are saved in the beginning of the buffer (overwriting
- * previously generated output).
- */
- static LOOP_BRANCH havege_cp( /* RETURN: branch to take */
- H_COLLECT *h_ctxt, /* IN: collection context */
- U_INT i, /* IN: collection offset */
- U_INT n, /* IN: iteration index */
- char *p) /* IN: code pointer */
- {
- U_INT block, fn, loop;
- if (0 != (fn = h_ctxt->havege_raw & DEBUG_RAW)) {
- loop = h_ctxt->havege_raw & ~fn;
- if (0 != (fn & DEBUG_RAW_OUT && i > RAW_SHIFT)) {
- block = i >> RAW_SHIFT;
- RESULT[block-2] = h_ctxt->havege_hardtick1;
- RESULT[block-1] = h_ctxt->havege_hardtick2;
- }
- if (n >= loop) {
- if (0 != (fn & DEBUG_RAW_IN) && i< h_ctxt->havege_szCollect) {
- block = RAW_INJECT + (i >> RAW_SHIFT);
- h_ctxt->havege_hardtick1 = RESULT[block++];
- h_ctxt->havege_hardtick2 = RESULT[block];
- }
- return LOOP_THIS;
- }
- }
- else loop = h_ctxt->havege_cdidx;
- if (loop <= 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 */
- {
- U_INT i=0,pt=0,inter=0;
- U_INT *Pt0, *Pt1, *Pt2, *Pt3, *Ptinter;
- 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));
- loop_exit:
- return ANDPT==0? 0 : 1;
- }
- /**
- * 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]);
- int i, sz;
- 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 & DEBUG_COMPILE)) {
- DEBUG_OUT("Address %u=%p\n", i, addr[i]);
- }
- RESULT[i] = abs(addr[i] - addr[LOOP_CT]);
- if (i > 0 && 0 != (h_ptr->havege_opts & DEBUG_LOOP)) {
- DEBUG_OUT("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 = 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];
- }