[Cryptech-Commits] [user/shatov/gost/streebog_tester] 01/01: Initial version of GOST 34.11-2012 hash core test program for Novena.

git at cryptech.is git at cryptech.is
Thu May 28 09:31:43 UTC 2015


This is an automated email from the git hooks/post-receive script.

meisterpaul1 at yandex.ru pushed a commit to branch master
in repository user/shatov/gost/streebog_tester.

commit 12d4c45ff1c40d8d1c91bb5dcab3d0642f91057a
Author: Pavel V. Shatov <meisterpaul1 at yandex.ru>
Date:   Thu May 28 13:27:55 2015 +0400

    Initial version of GOST 34.11-2012 hash core test program for Novena.
---
 Makefile              |  14 +
 novena-eim.c          | 708 ++++++++++++++++++++++++++++++++++++++++++++++++++
 novena-eim.h          |  52 ++++
 streebog_tester_eim.c | 568 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1342 insertions(+)

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..efbbe3a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,14 @@
+all: streebog_tester_eim
+
+.c.o:
+	gcc -c -Wall -o $@ $<
+
+streebog_tester_eim: streebog_tester_eim.o novena-eim.o
+	gcc -o $@ $^
+
+streebog_tester_eim.o: streebog_tester_eim.c novena-eim.h
+
+novena-eim.o: novena-eim.c novena-eim.h
+
+clean:
+	rm -f *.o streebog_tester_eim
diff --git a/novena-eim.c b/novena-eim.c
new file mode 100644
index 0000000..85bfac0
--- /dev/null
+++ b/novena-eim.c
@@ -0,0 +1,708 @@
+/* 
+ * novena-eim.c
+ * ------------
+ * This module contains the userland magic to set up and use the EIM bus.
+ *
+ * 
+ * Author: Pavel Shatov
+ * Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+#include "novena-eim.h"
+
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+#define MEMORY_DEVICE   "/dev/mem"
+
+#define IOMUXC_MUX_MODE_ALT0                    0       // 000
+
+#define IOMUXC_PAD_CTL_SRE_FAST                 1       // 1
+#define IOMUXC_PAD_CTL_DSE_33_OHM               7       // 111
+#define IOMUXC_PAD_CTL_SPEED_MEDIUM_10          2       // 10
+#define IOMUXC_PAD_CTL_ODE_DISABLED             0       // 0
+#define IOMUXC_PAD_CTL_PKE_DISABLED             0       // 0
+#define IOMUXC_PAD_CTL_PUE_PULL                 1       // 1
+#define IOMUXC_PAD_CTL_PUS_100K_OHM_PU          2       // 10
+#define IOMUXC_PAD_CTL_HYS_DISABLED             0       // 0
+
+#define CCM_CGR_OFF                             0       // 00
+#define CCM_CGR_ON_EXCEPT_STOP                  3       // 11
+
+
+//------------------------------------------------------------------------------
+// CPU Registers
+//------------------------------------------------------------------------------
+enum IMX6DQ_REGISTER_OFFSET
+{
+        IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B         = 0x020E00F8,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B          = 0x020E0100,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_RW            = 0x020E0104,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B         = 0x020E0108,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD00          = 0x020E0114,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD01          = 0x020E0118,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD02          = 0x020E011C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD03          = 0x020E0120,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD04          = 0x020E0124,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD05          = 0x020E0128,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD06          = 0x020E012C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD07          = 0x020E0130,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD08          = 0x020E0134,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD09          = 0x020E0138,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD10          = 0x020E013C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD11          = 0x020E0140,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD12          = 0x020E0144,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD13          = 0x020E0148,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD14          = 0x020E014C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD15          = 0x020E0150,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B        = 0x020E0154,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK          = 0x020E0158,
+
+        IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B         = 0x020E040C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B          = 0x020E0414,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_RW            = 0x020E0418,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B         = 0x020E041C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD00          = 0x020E0428,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD01          = 0x020E042C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD02          = 0x020E0430,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD03          = 0x020E0434,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD04          = 0x020E0438,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD05          = 0x020E043C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD06          = 0x020E0440,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD07          = 0x020E0444,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD08          = 0x020E0448,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD09          = 0x020E044C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD10          = 0x020E0450,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD11          = 0x020E0454,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD12          = 0x020E0458,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD13          = 0x020E045C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD14          = 0x020E0460,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD15          = 0x020E0464,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B        = 0x020E0468,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK          = 0x020E046C,
+        
+        CCM_CCGR6                               = 0x020C4080,
+        
+        EIM_CS0GCR1                             = 0x021B8000,
+        EIM_CS0GCR2                             = 0x021B8004,
+        EIM_CS0RCR1                             = 0x021B8008,
+        EIM_CS0RCR2                             = 0x021B800C,
+        EIM_CS0WCR1                             = 0x021B8010,
+        EIM_CS0WCR2                             = 0x021B8014,
+
+        EIM_WCR                                 = 0x021B8090,
+        EIM_WIAR                                = 0x021B8094,
+        EIM_EAR                                 = 0x021B8098,
+};
+
+
+//------------------------------------------------------------------------------
+// Structures
+//------------------------------------------------------------------------------
+struct IOMUXC_SW_MUX_CTL_PAD_EIM
+{
+        unsigned int    mux_mode                :  3;
+        unsigned int    reserved_3              :  1;
+        unsigned int    sion                    :  1;
+        unsigned int    reserved_31_5           : 27;
+};
+
+struct IOMUXC_SW_PAD_CTL_PAD_EIM
+{
+        unsigned int    sre                     : 1;
+        unsigned int    reserved_2_1            : 2;
+        unsigned int    dse                     : 3;
+        unsigned int    speed                   : 2;
+        unsigned int    reserved_10_8           : 3;
+        unsigned int    ode                     : 1;
+        unsigned int    pke                     : 1;
+        unsigned int    pue                     : 1;
+        unsigned int    pus                     : 2;
+        unsigned int    hys                     : 1;
+        unsigned int    reserved_31_17          : 15;
+};
+
+struct CCM_CCGR6
+{
+        unsigned int    cg0_usboh3              : 2;
+        unsigned int    cg1_usdhc1              : 2;
+        unsigned int    cg2_usdhc2              : 2;
+        unsigned int    cg3_usdhc3              : 2;
+        
+        unsigned int    cg3_usdhc4              : 2;
+        unsigned int    cg5_eim_slow            : 2;
+        unsigned int    cg6_vdoaxiclk           : 2;
+        unsigned int    cg7_vpu                 : 2;
+        
+        unsigned int    cg8_reserved            : 2;
+        unsigned int    cg9_reserved            : 2;
+        unsigned int    cg10_reserved           : 2;
+        unsigned int    cg11_reserved           : 2;
+        
+        unsigned int    cg12_reserved           : 2;
+        unsigned int    cg13_reserved           : 2;
+        unsigned int    cg14_reserved           : 2;
+        unsigned int    cg15_reserved           : 2;
+};
+
+struct EIM_CS_GCR1
+{
+        unsigned int    csen                    : 1;
+        unsigned int    swr                     : 1;
+        unsigned int    srd                     : 1;
+        unsigned int    mum                     : 1;
+        unsigned int    wfl                     : 1;
+        unsigned int    rfl                     : 1;
+        unsigned int    cre                     : 1;
+        unsigned int    crep                    : 1;
+        unsigned int    bl                      : 3;
+        unsigned int    wc                      : 1;
+        unsigned int    bcd                     : 2;
+        unsigned int    bcs                     : 2;
+        unsigned int    dsz                     : 3;
+        unsigned int    sp                      : 1;
+        unsigned int    csrec                   : 3;
+        unsigned int    aus                     : 1;
+        unsigned int    gbc                     : 3;
+        unsigned int    wp                      : 1;
+        unsigned int    psz                     : 4;
+};
+
+struct EIM_CS_GCR2
+{
+        unsigned int    adh                     :  2;
+        unsigned int    reserved_3_2            :  2;
+        unsigned int    daps                    :  4;
+        unsigned int    dae                     :  1;
+        unsigned int    dap                     :  1;
+        unsigned int    reserved_11_10          :  2;
+        unsigned int    mux16_byp_grant         :  1;
+        unsigned int    reserved_31_13          : 19;
+};
+
+struct EIM_CS_RCR1
+{
+        unsigned int    rcsn                    : 3;
+        unsigned int    reserved_3              : 1;
+        unsigned int    rcsa                    : 3;
+        unsigned int    reserved_7              : 1;
+        unsigned int    oen                     : 3;
+        unsigned int    reserved_11             : 1;
+        unsigned int    oea                     : 3;
+        unsigned int    reserved_15             : 1;
+        unsigned int    radvn                   : 3;
+        unsigned int    ral                     : 1;
+        unsigned int    radva                   : 3;
+        unsigned int    reserved_23             : 1;
+        unsigned int    rwsc                    : 6;
+        unsigned int    reserved_31_30          : 2;
+};
+
+struct EIM_CS_RCR2
+{
+        unsigned int    rben                    :  3;
+        unsigned int    rbe                     :  1;
+        unsigned int    rbea                    :  3;
+        unsigned int    reserved_7              :  1;
+        unsigned int    rl                      :  2;
+        unsigned int    reserved_11_10          :  2;
+        unsigned int    pat                     :  3;
+        unsigned int    apr                     :  1;
+        unsigned int    reserved_31_16          : 16;
+};
+
+struct EIM_CS_WCR1
+{
+        unsigned int    wcsn                    : 3;
+        unsigned int    wcsa                    : 3;
+        unsigned int    wen                     : 3;
+        unsigned int    wea                     : 3;
+        unsigned int    wben                    : 3;
+        unsigned int    wbea                    : 3;
+        unsigned int    wadvn                   : 3;
+        unsigned int    wadva                   : 3;
+        unsigned int    wwsc                    : 6;
+        unsigned int    wbed                    : 1;
+        unsigned int    wal                     : 1;
+};
+
+struct EIM_CS_WCR2
+{
+        unsigned int    wbcdd                   :  1;
+        unsigned int    reserved_31_1           : 31;
+};
+
+struct EIM_WCR
+{
+        unsigned int    bcm                     :  1;
+        unsigned int    gbcd                    :  2;
+        unsigned int    reserved_3              :  1;
+        unsigned int    inten                   :  1;
+        unsigned int    intpol                  :  1;
+        unsigned int    reserved_7_6            :  2;
+        unsigned int    wdog_en                 :  1;
+        unsigned int    wdog_limit              :  2;
+        unsigned int    reserved_31_11          : 21;
+};
+
+struct EIM_WIAR
+{
+        unsigned int    ips_req                 :  1;
+        unsigned int    ips_ack                 :  1;
+        unsigned int    irq                     :  1;
+        unsigned int    errst                   :  1;
+        unsigned int    aclk_en                 :  1;
+        unsigned int    reserved_31_5           : 27;
+};
+
+struct EIM_EAR
+{
+        unsigned int    error_addr              : 32;
+};
+
+
+//------------------------------------------------------------------------------
+// Variables
+//------------------------------------------------------------------------------
+static long     mem_page_size   = 0;
+static int      mem_dev_fd      = -1;
+static void *   mem_map_ptr     = MAP_FAILED;
+static off_t    mem_base_addr   = 0;
+
+
+//------------------------------------------------------------------------------
+// Prototypes
+//------------------------------------------------------------------------------
+static void     _eim_setup_iomuxc       (void);
+static void     _eim_setup_ccm          (void);
+static void     _eim_setup_eim          (void);
+static void     _eim_cleanup            (void);
+static off_t    _eim_calc_offset        (off_t);
+static void     _eim_remap_mem          (off_t);
+
+
+//------------------------------------------------------------------------------
+// Set up EIM bus. Returns 0 on success, -1 on failure.
+//------------------------------------------------------------------------------
+int eim_setup(void)
+{
+    // register cleanup function
+    if (atexit(_eim_cleanup) != 0) {
+        fprintf(stderr, "ERROR: atexit() failed.\n");
+        return -1;
+    }
+
+    // determine memory page size to use in mmap()
+    mem_page_size = sysconf(_SC_PAGESIZE);
+    if (mem_page_size < 1) {
+        fprintf(stderr, "ERROR: sysconf(_SC_PAGESIZE) == %ld\n", mem_page_size);
+        return -1;
+    }
+
+    // try to open memory device
+    mem_dev_fd = open(MEMORY_DEVICE, O_RDWR | O_SYNC);
+    if (mem_dev_fd == -1) {
+        fprintf(stderr, "ERROR: open(%s) failed.\n", MEMORY_DEVICE);
+        return -1;
+    }
+
+    // configure IOMUXC
+    _eim_setup_iomuxc();
+
+    // configure Clock Controller Module
+    _eim_setup_ccm();
+
+    /* We need to properly configure EIM mode and all the corresponding parameters.
+     * That's a lot of code, let's do it now.
+     */
+    _eim_setup_eim();
+
+    // done
+    return 0;
+}
+
+
+//------------------------------------------------------------------------------
+// Shut down EIM bus. This is called automatically on exit().
+//------------------------------------------------------------------------------
+static void _eim_cleanup(void)
+{
+    // unmap memory if needed
+    if (mem_map_ptr != MAP_FAILED)
+        if (munmap(mem_map_ptr, mem_page_size) != 0)
+            fprintf(stderr, "WARNING: munmap() failed.\n");
+
+    // close memory device if needed
+    if (mem_dev_fd != -1)
+        if (close(mem_dev_fd) != 0)
+            fprintf(stderr, "WARNING: close() failed.\n");
+}
+
+
+//------------------------------------------------------------------------------
+// Several blocks in the CPU have common pins. We use the I/O MUX Controller
+// to configure what block will actually use I/O pins. We wait for the EIM
+// module to be able to communicate with the on-board FPGA.
+//------------------------------------------------------------------------------
+static void _eim_setup_iomuxc(void)
+{
+    // create structures
+    struct IOMUXC_SW_MUX_CTL_PAD_EIM    reg_mux;                        // mux control register
+    struct IOMUXC_SW_PAD_CTL_PAD_EIM    reg_pad;                        // pad control register
+
+    // setup mux control register
+    reg_mux.mux_mode            = IOMUXC_MUX_MODE_ALT0;                 // ALT0 mode must be used for EIM
+    reg_mux.sion                = 0;                                    // forced input not needed
+    reg_mux.reserved_3          = 0;                                    // must be 0
+    reg_mux.reserved_31_5       = 0;                                    // must be 0
+
+    // setup pad control register
+    reg_pad.sre                 = IOMUXC_PAD_CTL_SRE_FAST;              // fast slew rate
+    reg_pad.dse                 = IOMUXC_PAD_CTL_DSE_33_OHM;            // highest drive strength
+    reg_pad.speed               = IOMUXC_PAD_CTL_SPEED_MEDIUM_10;       // medium speed
+    reg_pad.ode                 = IOMUXC_PAD_CTL_ODE_DISABLED;          // open drain not needed
+    reg_pad.pke                 = IOMUXC_PAD_CTL_PKE_DISABLED;          // neither pull nor keeper are needed
+    reg_pad.pue                 = IOMUXC_PAD_CTL_PUE_PULL;              // doesn't matter actually, because PKE is disabled
+    reg_pad.pus                 = IOMUXC_PAD_CTL_PUS_100K_OHM_PU;       // doesn't matter actually, because PKE is disabled
+    reg_pad.hys                 = IOMUXC_PAD_CTL_HYS_DISABLED;          // use CMOS, not Schmitt trigger input
+    reg_pad.reserved_2_1        = 0;                                    // must be 0
+    reg_pad.reserved_10_8       = 0;                                    // must be 0
+    reg_pad.reserved_31_17      = 0;                                    // must be 0
+
+    // all the pins must be configured to use the same ALT0 mode
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B,       (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_RW,          (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B,       (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD00,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD01,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD02,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD03,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD04,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD05,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD06,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD07,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD08,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD09,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD10,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD11,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD12,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD13,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD14,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD15,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B,      (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK,        (uint32_t *)&reg_mux);
+
+    // we need to configure all the I/O pads too
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B,       (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_RW,          (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B,       (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD00,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD01,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD02,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD03,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD04,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD05,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD06,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD07,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD08,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD09,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD10,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD11,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD12,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD13,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD14,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD15,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B,      (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK,        (uint32_t *)&reg_pad);
+}
+
+
+//------------------------------------------------------------------------------
+// Configure Clock Controller Module to enable clocking of EIM block.
+//------------------------------------------------------------------------------
+static void _eim_setup_ccm(void)
+{
+    // create structure
+    struct CCM_CCGR6 ccm_ccgr6;
+
+    // read register
+    eim_read_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
+
+    // modify register
+    ccm_ccgr6.cg0_usboh3                = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg1_usdhc1                = CCM_CGR_OFF;
+    ccm_ccgr6.cg2_usdhc2                = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg3_usdhc3                = CCM_CGR_ON_EXCEPT_STOP;
+
+    ccm_ccgr6.cg3_usdhc4                = CCM_CGR_OFF;
+    ccm_ccgr6.cg5_eim_slow              = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg6_vdoaxiclk             = CCM_CGR_OFF;
+    ccm_ccgr6.cg7_vpu                   = CCM_CGR_OFF;
+
+    ccm_ccgr6.cg8_reserved              = 0;
+    ccm_ccgr6.cg9_reserved              = 0;
+    ccm_ccgr6.cg10_reserved             = 0;
+    ccm_ccgr6.cg11_reserved             = 0;
+    ccm_ccgr6.cg12_reserved             = 0;
+    ccm_ccgr6.cg13_reserved             = 0;
+    ccm_ccgr6.cg14_reserved             = 0;
+    ccm_ccgr6.cg15_reserved             = 0;
+
+    // write register
+    eim_write_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
+}
+
+
+//------------------------------------------------------------------------------
+// Configure EIM mode and all the corresponding parameters. That's a lot of code.
+//------------------------------------------------------------------------------
+static void _eim_setup_eim(void)
+{
+    // create structures
+    struct EIM_CS_GCR1  gcr1;
+    struct EIM_CS_GCR2  gcr2;
+    struct EIM_CS_RCR1  rcr1;
+    struct EIM_CS_RCR2  rcr2;
+    struct EIM_CS_WCR1  wcr1;
+    struct EIM_CS_WCR2  wcr2;
+
+    struct EIM_WCR              wcr;
+    struct EIM_WIAR             wiar;
+    struct EIM_EAR              ear;
+
+    // read all the registers
+    eim_read_32(EIM_CS0GCR1, (uint32_t *)&gcr1);
+    eim_read_32(EIM_CS0GCR2, (uint32_t *)&gcr2);
+    eim_read_32(EIM_CS0RCR1, (uint32_t *)&rcr1);
+    eim_read_32(EIM_CS0RCR2, (uint32_t *)&rcr2);
+    eim_read_32(EIM_CS0WCR1, (uint32_t *)&wcr1);
+    eim_read_32(EIM_CS0WCR2, (uint32_t *)&wcr2);
+
+    eim_read_32(EIM_WCR,        (uint32_t *)&wcr);
+    eim_read_32(EIM_WIAR,       (uint32_t *)&wiar);
+    eim_read_32(EIM_EAR,        (uint32_t *)&ear);
+
+    // manipulate registers as needed
+    gcr1.csen           = 1;    // chip select is enabled
+    gcr1.swr            = 1;    // write is sync
+    gcr1.srd            = 1;    // read is sync
+    gcr1.mum            = 1;    // address and data are multiplexed
+    gcr1.wfl            = 0;    // write latency is not fixed
+    gcr1.rfl            = 0;    // read latency is not fixed
+    gcr1.cre            = 0;    // CRE signal not needed
+    //gcr1.crep         = x;    // don't care, CRE not used
+    gcr1.bl             = 4;    // burst length
+    gcr1.wc             = 0;    // write is not continuous
+    gcr1.bcd            = 3;    // BCLK divisor is 3+1=4
+    gcr1.bcs            = 1;    // delay from ~CS to BCLK is 1 cycle
+    gcr1.dsz            = 1;    // 16 bits per databeat at DATA[15:0]
+    gcr1.sp             = 0;    // supervisor protection is disabled
+    gcr1.csrec          = 1;    // ~CS recovery is 1 cycle
+    gcr1.aus            = 1;    // address is not shifted
+    gcr1.gbc            = 1;    // ~CS gap is 1 cycle
+    gcr1.wp             = 0;    // write protection is not enabled
+    //gcr1.psz          = x;    // don't care, page mode is not used
+
+    gcr2.adh            = 0;    // address hold duration is 1 cycle
+    //gcr2.daps         = x;    // don't care, DTACK is not used
+    gcr2.dae            = 0;    // DTACK is not used
+    //gcr2.dap          = x;    // don't care, DTACK is not used
+    gcr2.mux16_byp_grant= 1;    // enable grant mechanism
+    gcr2.reserved_3_2   = 0;    // must be 0
+    gcr2.reserved_11_10 = 0;    // must be 0
+    gcr2.reserved_31_13 = 0;    // must be 0
+
+    //rcr1.rcsn         = x;    // don't care in sync mode
+    rcr1.rcsa           = 0;    // no delay for ~CS needed
+    //rcr1.oen          = x;    // don't care in sync mode
+    rcr1.oea            = 0;    // no delay for ~OE needed
+    rcr1.radvn          = 0;    // no delay for ~LBA needed
+    rcr1.ral            = 0;    // clear ~LBA when needed
+    rcr1.radva          = 0;    // no delay for ~LBA needed
+    rcr1.rwsc           = 1;    // one wait state
+    rcr1.reserved_3     = 0;    // must be 0
+    rcr1.reserved_7     = 0;    // must be 0
+    rcr1.reserved_11    = 0;    // must be 0
+    rcr1.reserved_15    = 0;    // must be 0
+    rcr1.reserved_23    = 0;    // must be 0
+    rcr1.reserved_31_30 = 0;    // must be 0
+
+    //rcr2.rben         = x;    // don't care in sync mode
+    rcr2.rbe            = 0;    // BE is disabled
+    //rcr2.rbea         = x;    // don't care when BE is not used
+    rcr2.rl             = 0;    // read latency is 0
+    //rcr2.pat          = x;    // don't care when page read is not used
+    rcr2.apr            = 0;    // page read mode is not used
+    rcr2.reserved_7     = 0;    // must be 0
+    rcr2.reserved_11_10 = 0;    // must be 0
+    rcr2.reserved_31_16 = 0;    // must be 0
+
+    //wcr1.wcsn         = x;    // don't care in sync mode
+    wcr1.wcsa           = 0;    // no delay for ~CS needed
+    //wcr1.wen          = x;    // don't care in sync mode
+    wcr1.wea            = 0;    // no delay for ~WR_N needed
+    //wcr1.wben         = x;    // don't care in sync mode
+    //wcr1.wbea         = x;    // don't care in sync mode
+    wcr1.wadvn          = 0;    // no delay for ~LBA needed
+    wcr1.wadva          = 0;    // no delay for ~LBA needed
+    wcr1.wwsc           = 1;    // no wait state in needed
+    wcr1.wbed           = 1;    // BE is disabled
+    wcr1.wal            = 0;    // clear ~LBA when needed
+
+    wcr2.wbcdd          = 0;    // write clock division is not needed
+    wcr2.reserved_31_1  = 0;    // must be 0
+
+    wcr.bcm             = 0;    // clock is only active during access
+    //wcr.gbcd          = x;    // don't care when BCM=0
+    wcr.inten           = 0;    // interrupt is not used
+    //wcr.intpol        = x;    // don't care when interrupt is not used
+    wcr.wdog_en         = 1;    // watchdog is enabled
+    wcr.wdog_limit      = 00;   // timeout is 128 BCLK cycles
+    wcr.reserved_3      = 0;    // must be 0
+    wcr.reserved_7_6    = 0;    // must be 0
+    wcr.reserved_31_11  = 0;    // must be 0
+
+    wiar.ips_req        = 0;    // IPS not needed
+    wiar.ips_ack        = 0;    // IPS not needed
+    //wiar.irq          = x;    // don't touch
+    //wiar.errst        = x;    // don't touch
+    wiar.aclk_en        = 1;    // clock is enabled
+    wiar.reserved_31_5  = 0;    // must be 0
+
+    //ear.error_addr    = x;    // read-only
+
+    // write modified registers
+    eim_write_32(EIM_CS0GCR1,   (uint32_t *)&gcr1);
+    eim_write_32(EIM_CS0GCR2,   (uint32_t *)&gcr2);
+    eim_write_32(EIM_CS0RCR1,   (uint32_t *)&rcr1);
+    eim_write_32(EIM_CS0RCR2,   (uint32_t *)&rcr2);
+    eim_write_32(EIM_CS0WCR1,   (uint32_t *)&wcr1);
+    eim_write_32(EIM_CS0WCR2,   (uint32_t *)&wcr2);
+    eim_write_32(EIM_WCR,               (uint32_t *)&wcr);
+    eim_write_32(EIM_WIAR,      (uint32_t *)&wiar);
+/*  eim_write_32(EIM_EAR,       (uint32_t *)&ear);*/
+}
+
+
+//------------------------------------------------------------------------------
+// Write a 32-bit word to EIM.
+// If EIM is not set up correctly, this will abort with a bus error.
+//------------------------------------------------------------------------------
+void eim_write_32(off_t offset, uint32_t *pvalue)
+{
+    // calculate memory offset
+    uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
+
+    // write data to memory
+    memcpy(ptr, pvalue, sizeof(uint32_t));
+}
+
+//------------------------------------------------------------------------------
+// Read a 32-bit word from EIM.
+// If EIM is not set up correctly, this will abort with a bus error.
+//------------------------------------------------------------------------------
+void eim_read_32(off_t offset, uint32_t *pvalue)
+{
+    // calculate memory offset
+    uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
+
+    // read data from memory
+    memcpy(pvalue, ptr, sizeof(uint32_t));
+}
+
+
+//------------------------------------------------------------------------------
+// Calculate an offset into the currently-mapped EIM page.
+//------------------------------------------------------------------------------
+static off_t _eim_calc_offset(off_t offset)
+{
+    // make sure that memory is mapped
+    if (mem_map_ptr == MAP_FAILED)
+        _eim_remap_mem(offset);
+
+    // calculate starting and ending addresses of currently mapped page
+    off_t offset_low    = mem_base_addr;
+    off_t offset_high   = mem_base_addr + (mem_page_size - 1);
+
+    // check that offset is in currently mapped page, remap new page otherwise
+    if ((offset < offset_low) || (offset > offset_high))
+        _eim_remap_mem(offset);
+
+    // calculate pointer
+    return (off_t)mem_map_ptr + (offset - mem_base_addr);
+}
+
+
+//------------------------------------------------------------------------------
+// Map in a new EIM page.
+//------------------------------------------------------------------------------
+static void _eim_remap_mem(off_t offset)
+{
+    // unmap old memory page if needed
+    if (mem_map_ptr != MAP_FAILED) {
+        if (munmap(mem_map_ptr, mem_page_size) != 0) {
+            fprintf(stderr, "ERROR: munmap() failed.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // calculate starting address of new page
+    while (offset % mem_page_size)
+        offset--;
+
+    // try to map new memory page
+    mem_map_ptr = mmap(NULL, mem_page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                       mem_dev_fd, offset);
+    if (mem_map_ptr == MAP_FAILED) {
+        fprintf(stderr, "ERROR: mmap() failed.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // save last mapped page address
+    mem_base_addr = offset;
+}
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/novena-eim.h b/novena-eim.h
new file mode 100644
index 0000000..75613bf
--- /dev/null
+++ b/novena-eim.h
@@ -0,0 +1,52 @@
+/* 
+ * novena-eim.h
+ * ------------
+ * This module contains the userland magic to set up and use the EIM bus.
+ *
+ * 
+ * Author: Pavel Shatov
+ * Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define EIM_BASE_ADDR 0x08000000
+
+/* Set up EIM bus.
+ * Returns 0 on success, -1 on failure.
+ */
+int  eim_setup(void);
+
+/* Write a 32-bit word to EIM.
+ * If EIM is not set up correctly, this will abort with a bus error.
+ */
+void eim_write_32(off_t, uint32_t *);
+
+/* Read a 32-bit word from EIM.
+ * If EIM is not set up correctly, this will abort with a bus error.
+ */
+void eim_read_32(off_t, uint32_t *);
diff --git a/streebog_tester_eim.c b/streebog_tester_eim.c
new file mode 100644
index 0000000..eceb6cd
--- /dev/null
+++ b/streebog_tester_eim.c
@@ -0,0 +1,568 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include "novena-eim.h"
+
+int debug = 0;
+int quiet = 0;
+int repeat = 0;
+
+#define SEGMENT_OFFSET_GLOBALS  EIM_BASE_ADDR + 0x000000
+#define SEGMENT_OFFSET_HASHES   EIM_BASE_ADDR + 0x010000
+#define SEGMENT_OFFSET_RNGS     EIM_BASE_ADDR + 0x020000
+#define SEGMENT_OFFSET_CIPHERS  EIM_BASE_ADDR + 0x030000
+
+/* addresses and codes common to all cores */
+#define ADDR_NAME0              (0x00 << 2)
+#define ADDR_NAME1              (0x01 << 2)
+#define ADDR_VERSION            (0x02 << 2)
+
+/* addresses and codes common to all hash cores */
+#define ADDR_CTRL               (0x08 << 2)
+#define CTRL_INIT_CMD           1
+#define CTRL_NEXT_CMD           2
+#define ADDR_STATUS             (0x09 << 2)
+#define STATUS_READY_BIT        1
+#define STATUS_VALID_BIT        2
+#define ADDR_BLOCK              (0x10 << 2)
+#define ADDR_DIGEST             (0x20 << 2)
+#define HASH_CORE_SIZE          (0x100 << 2)
+
+/* addresses and codes for the specific hash cores */
+#define STREEBOG_ADDR_BASE        SEGMENT_OFFSET_HASHES + (3*HASH_CORE_SIZE)
+#define STREEBOG_ADDR_NAME0       STREEBOG_ADDR_BASE + ADDR_NAME0
+#define STREEBOG_ADDR_NAME1       STREEBOG_ADDR_BASE + ADDR_NAME1
+#define STREEBOG_ADDR_VERSION     STREEBOG_ADDR_BASE + ADDR_VERSION
+#define STREEBOG_ADDR_CTRL        STREEBOG_ADDR_BASE + ADDR_CTRL
+#define STREEBOG_ADDR_STATUS      STREEBOG_ADDR_BASE + ADDR_STATUS
+#define STREEBOG_ADDR_BLOCK_BITS  STREEBOG_ADDR_BASE + (0x0a << 2)
+#define STREEBOG_ADDR_MODE		  STREEBOG_ADDR_BASE + (0x0b << 2)
+#define STREEBOG_ADDR_BLOCK       STREEBOG_ADDR_BASE + ADDR_BLOCK
+#define STREEBOG_ADDR_DIGEST      STREEBOG_ADDR_BASE + ADDR_DIGEST
+#define CTRL_FINAL_CMD            4
+#define STREEBOG_MODE_512         0
+#define STREEBOG_MODE_256         1
+#define STREEBOG_BLOCK_LEN        512 / 8
+#define STREEBOG_DIGEST_LEN_512   512 / 8
+#define STREEBOG_DIGEST_LEN_256   256 / 8
+
+
+const uint8_t GOST_SINGLE[] =
+{ 0x01, 0x32, 0x31, 0x30, 0x39, 0x38, 0x37, 0x36,
+  0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x39, 0x38,
+  0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
+  0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32,
+  0x31, 0x30, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34,
+  0x33, 0x32, 0x31, 0x30, 0x39, 0x38, 0x37, 0x36,
+  0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x39, 0x38,
+  0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30 };
+
+const uint8_t GOST_DOUBLE_FIRST[] = 
+{ 0xfb, 0xea, 0xfa, 0xeb, 0xef, 0x20, 0xff, 0xfb,
+  0xf0, 0xe1, 0xe0, 0xf0, 0xf5, 0x20, 0xe0, 0xed,
+  0x20, 0xe8, 0xec, 0xe0, 0xeb, 0xe5, 0xf0, 0xf2,
+  0xf1, 0x20, 0xff, 0xf0, 0xee, 0xec, 0x20, 0xf1,
+  0x20, 0xfa, 0xf2, 0xfe, 0xe5, 0xe2, 0x20, 0x2c,
+  0xe8, 0xf6, 0xf3, 0xed, 0xe2, 0x20, 0xe8, 0xe6,
+  0xee, 0xe1, 0xe8, 0xf0, 0xf2, 0xd1, 0x20, 0x2c,
+  0xe8, 0xf0, 0xf2, 0xe5, 0xe2, 0x20, 0xe5, 0xd1 };
+  
+const uint8_t GOST_DOUBLE_SECOND[] = 
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0xfb, 0xe2, 0xe5, 0xf0, 0xee, 0xe3, 0xc8, 0x20 };
+  
+const uint32_t GOST_SINGLE_LENGTH = 504;
+
+const uint32_t GOST_DOUBLE_LENGTH_FIRST  = 512;
+const uint32_t GOST_DOUBLE_LENGTH_SECOND =  64;
+
+const uint8_t GOST_SINGLE_DIGEST_512[] =
+{ 0x48, 0x6f, 0x64, 0xc1, 0x91, 0x78, 0x79, 0x41,
+  0x7f, 0xef, 0x08, 0x2b, 0x33, 0x81, 0xa4, 0xe2,
+  0x11, 0xc3, 0x24, 0xf0, 0x74, 0x65, 0x4c, 0x38,
+  0x82, 0x3a, 0x7b, 0x76, 0xf8, 0x30, 0xad, 0x00,
+  0xfa, 0x1f, 0xba, 0xe4, 0x2b, 0x12, 0x85, 0xc0,
+  0x35, 0x2f, 0x22, 0x75, 0x24, 0xbc, 0x9a, 0xb1,
+  0x62, 0x54, 0x28, 0x8d, 0xd6, 0x86, 0x3d, 0xcc,
+  0xd5, 0xb9, 0xf5, 0x4a, 0x1a, 0xd0, 0x54, 0x1b };
+  
+const uint8_t GOST_SINGLE_DIGEST_256[] =
+{ 0x00, 0x55, 0x7b, 0xe5, 0xe5, 0x84, 0xfd, 0x52,
+  0xa4, 0x49, 0xb1, 0x6b, 0x02, 0x51, 0xd0, 0x5d,
+  0x27, 0xf9, 0x4a, 0xb7, 0x6c, 0xba, 0xa6, 0xda,
+  0x89, 0x0b, 0x59, 0xd8, 0xef, 0x1e, 0x15, 0x9d };
+  
+const uint8_t GOST_DOUBLE_DIGEST_512[] =
+{ 0x28, 0xfb, 0xc9, 0xba, 0xda, 0x03, 0x3b, 0x14,
+  0x60, 0x64, 0x2b, 0xdc, 0xdd, 0xb9, 0x0c, 0x3f,
+  0xb3, 0xe5, 0x6c, 0x49, 0x7c, 0xcd, 0x0f, 0x62,
+  0xb8, 0xa2, 0xad, 0x49, 0x35, 0xe8, 0x5f, 0x03,
+  0x76, 0x13, 0x96, 0x6d, 0xe4, 0xee, 0x00, 0x53,
+  0x1a, 0xe6, 0x0f, 0x3b, 0x5a, 0x47, 0xf8, 0xda,
+  0xe0, 0x69, 0x15, 0xd5, 0xf2, 0xf1, 0x94, 0x99,
+  0x6f, 0xca, 0xbf, 0x26, 0x22, 0xe6, 0x88, 0x1e };
+  
+const uint8_t GOST_DOUBLE_DIGEST_256[] =
+{ 0x50, 0x8f, 0x7e, 0x55, 0x3c, 0x06, 0x50, 0x1d,
+  0x74, 0x9a, 0x66, 0xfc, 0x28, 0xc6, 0xca, 0xc0,
+  0xb0, 0x05, 0x74, 0x6d, 0x97, 0x53, 0x7f, 0xa8,
+  0x5d, 0x9e, 0x40, 0x90, 0x4e, 0xfe, 0xd2, 0x9d };
+
+
+/* ---------------- test-case low-level code ---------------- */
+
+void dump(char *label, const uint8_t *buf, int len)
+{
+    if (debug) {
+        int i;
+        printf("%s [", label);
+        for (i = 0; i < len; ++i)
+            printf(" %02x", buf[i]);
+        printf(" ]\n");
+    }
+}
+
+int tc_write(off_t offset, const uint8_t *buf, int len)
+{
+    dump("write ", buf, len);
+
+    for (; len > 0; offset += 4, buf += 4, len -= 4) {
+        uint32_t val;
+        val = htonl(*(uint32_t *)buf);
+        eim_write_32(offset, &val);
+    }
+
+    return 0;
+}
+
+int tc_read(off_t offset, uint8_t *buf, int len)
+{
+    uint8_t *rbuf = buf;
+    int rlen = len;
+
+    for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) {
+        uint32_t val;
+        eim_read_32(offset, &val);
+        *(uint32_t *)rbuf = ntohl(val);
+    }
+
+    dump("read  ", buf, len);
+
+    return 0;
+}
+
+int tc_expected(off_t offset, const uint8_t *expected, int len)
+{
+    uint8_t *buf;
+    int i;
+
+    buf = malloc(len);
+    if (buf == NULL) {
+        perror("malloc");
+        return 1;
+    }
+    dump("expect", expected, len);
+
+    if (tc_read(offset, buf, len) != 0)
+        goto errout;
+
+    for (i = 0; i < len; ++i)
+        if (buf[i] != expected[i]) {
+            fprintf(stderr, "response byte %d: expected 0x%02x, got 0x%02x\n",
+                    i, expected[i], buf[i]);
+            goto errout;
+        }
+
+    free(buf);
+    return 0;
+errout:
+    free(buf);
+    return 1;
+}
+
+int tc_block_bits(off_t offset, uint32_t bits)
+{
+    uint8_t buf[4] = {0, 0, (uint8_t)(bits >> 8), (uint8_t)bits};
+    return tc_write(offset, buf, 4);
+}
+
+int tc_mode(off_t offset, char mode)
+{
+    uint8_t buf[4] = { 0, 0, 0, mode };
+
+    return tc_write(offset, buf, 4);
+}
+
+int tc_init(off_t offset)
+{
+    uint8_t buf[4] = { 0, 0, 0, CTRL_INIT_CMD };
+
+    return tc_write(offset, buf, 4);
+}
+
+int tc_next(off_t offset)
+{
+	uint8_t buf_clear[4] = { 0, 0, 0, 0 };
+	uint8_t buf_next[4]  = { 0, 0, 0, CTRL_NEXT_CMD };
+	
+    tc_write(offset, buf_clear, 4);
+    
+    return tc_write(offset, buf_next, 4);
+}
+
+int tc_final(off_t offset)
+{
+    uint8_t buf[4] = { 0, 0, 0, CTRL_FINAL_CMD };
+
+    return tc_write(offset, buf, 4);
+}
+
+int tc_wait(off_t offset, uint8_t status)
+{
+    uint8_t buf[4];
+
+#if 0
+    do {
+        if (tc_read(offset, buf, 4) != 0)
+            return 1;
+    } while (!(buf[3] & status));
+
+    return 0;
+#else
+    int i;
+    for (i = 0; i < 100; ++i) {
+        if (tc_read(offset, buf, 4) != 0)
+            return 1;
+        if (buf[3] & status)
+            return 0;
+    }
+    fprintf(stderr, "tc_wait timed out\n");
+    return 1;
+#endif
+}
+
+int tc_wait_ready(off_t offset)
+{
+    return tc_wait(offset, STATUS_READY_BIT);
+}
+
+int tc_wait_valid(off_t offset)
+{
+    return tc_wait(offset, STATUS_VALID_BIT);
+}
+
+
+/* ---------------- Streebog test cases ---------------- */
+
+/* TC0: Read name and version from Streebog core. */
+int TC0(void)
+{
+    uint8_t name0[4]   = { 's', 't', 'r', 'e'};
+    uint8_t name1[4]   = { 'e', 'b', 'o', 'g'};
+    uint8_t version[4] = { '0', '.', '1', '0'};
+
+    if (!quiet)
+        printf("TC0: Reading name and version words from Streebog core.\n");
+
+    return
+        tc_expected(STREEBOG_ADDR_NAME0, name0, 4) ||
+        tc_expected(STREEBOG_ADDR_NAME1, name1, 4) ||
+        tc_expected(STREEBOG_ADDR_VERSION, version, 4);
+}
+
+/* TC1: Streebog single block message for 512-bit hash mode. */
+int TC1(void)
+{
+    const uint8_t *block = GOST_SINGLE;
+    const uint8_t *expected = GOST_SINGLE_DIGEST_512;
+    int ret;
+
+    if (!quiet)
+        printf("TC1: Short (single block) message test for Streebog (512-bit mode).\n");
+
+	/* Enable 512-bit mode. */
+	tc_mode(STREEBOG_ADDR_MODE, STREEBOG_MODE_512);
+	/* Start initial block hashing. */
+    tc_init(STREEBOG_ADDR_CTRL);
+	
+    /* Write block to Streebog. */
+    tc_write(STREEBOG_ADDR_BLOCK, block, STREEBOG_BLOCK_LEN);
+	/* Write block length to Streebog. */
+	tc_block_bits(STREEBOG_ADDR_BLOCK_BITS, GOST_SINGLE_LENGTH);
+	/* Process block. */
+	tc_next(STREEBOG_ADDR_CTRL);
+	/* Wait for block to be processed. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+
+	/* Perform final transformation. */
+	tc_final(STREEBOG_ADDR_CTRL);
+	/* Wait for hash to be produces. */
+    tc_wait_valid(STREEBOG_ADDR_STATUS);
+    /* Extract the digest. */
+    ret = tc_expected(STREEBOG_ADDR_DIGEST, expected, STREEBOG_DIGEST_LEN_512);
+	
+	/* Make sure that core is idle. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+	
+    return ret;
+}
+
+/* TC2: Streebog double block message for 512-bit hash mode. */
+int TC2(void)
+{
+    const uint8_t *block1 = GOST_DOUBLE_FIRST;
+	const uint8_t *block2 = GOST_DOUBLE_SECOND;
+    const uint8_t *expected = GOST_DOUBLE_DIGEST_512;
+    int ret;
+
+    if (!quiet)
+        printf("TC2: Long (double block) message test for Streebog (512-bit mode).\n");
+
+	/* Enable 512-bit mode. */
+	tc_mode(STREEBOG_ADDR_MODE, STREEBOG_MODE_512);
+	/* Start initial block hashing. */
+    tc_init(STREEBOG_ADDR_CTRL);
+	
+    /* Write block to Streebog. */
+    tc_write(STREEBOG_ADDR_BLOCK, block1, STREEBOG_BLOCK_LEN);
+	/* Write block length to Streebog. */
+	tc_block_bits(STREEBOG_ADDR_BLOCK_BITS, GOST_DOUBLE_LENGTH_FIRST);
+	/* Process block. */
+	tc_next(STREEBOG_ADDR_CTRL);
+	/* Wait for block to be processed. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+	
+	/* Write block to Streebog. */
+    tc_write(STREEBOG_ADDR_BLOCK, block2, STREEBOG_BLOCK_LEN);
+	/* Write block length to Streebog. */
+	tc_block_bits(STREEBOG_ADDR_BLOCK_BITS, GOST_DOUBLE_LENGTH_SECOND);
+	/* Process block. */
+	tc_next(STREEBOG_ADDR_CTRL);
+	/* Wait for block to be processed. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+
+	/* Perform final transformation. */
+	tc_final(STREEBOG_ADDR_CTRL);
+	/* Wait for hash to be produces. */
+    tc_wait_valid(STREEBOG_ADDR_STATUS);
+    /* Extract the digest. */
+    ret = tc_expected(STREEBOG_ADDR_DIGEST, expected, STREEBOG_DIGEST_LEN_512);
+	
+	/* Make sure that core is idle. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+	
+    return ret;
+}
+
+
+/* TC3: Streebog single block message for 256-bit hash mode. */
+int TC3(void)
+{
+    const uint8_t *block = GOST_SINGLE;
+    const uint8_t *expected = GOST_SINGLE_DIGEST_256;
+    int ret;
+
+    if (!quiet)
+        printf("TC3: Short (single block) message test for Streebog (256-bit mode).\n");
+
+	/* Enable 512-bit mode. */
+	tc_mode(STREEBOG_ADDR_MODE, STREEBOG_MODE_256);
+	/* Start initial block hashing. */
+    tc_init(STREEBOG_ADDR_CTRL);
+	
+    /* Write block to Streebog. */
+    tc_write(STREEBOG_ADDR_BLOCK, block, STREEBOG_BLOCK_LEN);
+	/* Write block length to Streebog. */
+	tc_block_bits(STREEBOG_ADDR_BLOCK_BITS, GOST_SINGLE_LENGTH);
+	/* Process block. */
+	tc_next(STREEBOG_ADDR_CTRL);
+	/* Wait for block to be processed. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+
+	/* Perform final transformation. */
+	tc_final(STREEBOG_ADDR_CTRL);
+	/* Wait for hash to be produces. */
+    tc_wait_valid(STREEBOG_ADDR_STATUS);
+    /* Extract the digest. */
+    ret = tc_expected(STREEBOG_ADDR_DIGEST, expected, STREEBOG_DIGEST_LEN_256);
+	
+	/* Make sure that core is idle. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+	
+    return ret;
+}
+
+
+/* TC4: Streebog double block message for 256-bit hash mode. */
+int TC4(void)
+{
+	const uint8_t *block1 = GOST_DOUBLE_FIRST;
+	const uint8_t *block2 = GOST_DOUBLE_SECOND;
+    const uint8_t *expected = GOST_DOUBLE_DIGEST_256;
+    int ret;
+
+    if (!quiet)
+        printf("TC4: Long (double block) message test for Streebog (256-bit mode).\n");
+
+	/* Enable 512-bit mode. */
+	tc_mode(STREEBOG_ADDR_MODE, STREEBOG_MODE_256);
+	/* Start initial block hashing. */
+    tc_init(STREEBOG_ADDR_CTRL);
+	
+    /* Write block to Streebog. */
+    tc_write(STREEBOG_ADDR_BLOCK, block1, STREEBOG_BLOCK_LEN);
+	/* Write block length to Streebog. */
+	tc_block_bits(STREEBOG_ADDR_BLOCK_BITS, GOST_DOUBLE_LENGTH_FIRST);
+	/* Process block. */
+	tc_next(STREEBOG_ADDR_CTRL);
+	/* Wait for block to be processed. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+	
+	/* Write block to Streebog. */
+    tc_write(STREEBOG_ADDR_BLOCK, block2, STREEBOG_BLOCK_LEN);
+	/* Write block length to Streebog. */
+	tc_block_bits(STREEBOG_ADDR_BLOCK_BITS, GOST_DOUBLE_LENGTH_SECOND);
+	/* Process block. */
+	tc_next(STREEBOG_ADDR_CTRL);
+	/* Wait for block to be processed. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+
+	/* Perform final transformation. */
+	tc_final(STREEBOG_ADDR_CTRL);
+	/* Wait for hash to be produces. */
+    tc_wait_valid(STREEBOG_ADDR_STATUS);
+    /* Extract the digest. */
+    ret = tc_expected(STREEBOG_ADDR_DIGEST, expected, STREEBOG_DIGEST_LEN_256);
+	
+	/* Make sure that core is idle. */
+	tc_wait_ready(STREEBOG_ADDR_STATUS);
+	
+    return ret;
+}
+
+/* ---------------- main ---------------- */
+
+/* signal handler for ctrl-c to end repeat testing */
+unsigned long iter = 0;
+struct timeval tv_start, tv_end;
+void sighandler(int unused)
+{
+    double tv_diff;
+
+    gettimeofday(&tv_end, NULL);
+    tv_diff = (double)(tv_end.tv_sec - tv_start.tv_sec) +
+        (double)(tv_end.tv_usec - tv_start.tv_usec)/1000000;
+    printf("\n%lu iterations in %.3f seconds (%.3f iterations/sec)\n",
+           iter, tv_diff, (double)iter/tv_diff);
+    exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char *argv[])
+{
+    typedef int (*tcfp)(void);
+    tcfp all_tests[] = { TC0, TC1, TC2, TC3, TC4 };
+
+    char *usage = "Usage: %s [-h] [-d] [-q] [-r] tc...\n";
+    int i, j, opt;
+
+    while ((opt = getopt(argc, argv, "h?dqr")) != -1) {
+        switch (opt) {
+        case 'h':
+        case '?':
+            printf(usage, argv[0]);
+            return EXIT_SUCCESS;
+        case 'd':
+            debug = 1;
+            break;
+        case 'q':
+            quiet = 1;
+            break;
+        case 'r':
+            repeat = 1;
+            break;
+        default:
+            fprintf(stderr, usage, argv[0]);
+            return EXIT_FAILURE;
+        }
+    }
+
+    /* set up EIM */
+    if (eim_setup() != 0) {
+        fprintf(stderr, "EIM setup failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* repeat one test until interrupted */
+    if (repeat) {
+        tcfp tc;
+        if (optind != argc - 1) {
+            fprintf(stderr, "only one test case can be repeated\n");
+            return EXIT_FAILURE;
+        }
+        j = atoi(argv[optind]);
+        if (j < 0 || j >= sizeof(all_tests)/sizeof(all_tests[0])) {
+            fprintf(stderr, "invalid test number %s\n", argv[optind]);
+            return EXIT_FAILURE;
+        }
+        tc = (all_tests[j]);
+        srand(time(NULL));
+        signal(SIGINT, sighandler);
+        gettimeofday(&tv_start, NULL);
+        while (1) {
+            ++iter;
+            if ((iter & 0xffff) == 0) {
+                printf(".");
+                fflush(stdout);
+            }
+            if (tc() != 0)
+                sighandler(0);
+        }
+        return EXIT_SUCCESS;    /*NOTREACHED*/
+    }
+
+    /* no args == run all tests */
+    if (optind >= argc) {
+        for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+            if (all_tests[j]() != 0)
+                return EXIT_FAILURE;
+        return EXIT_SUCCESS;
+    }
+
+    /* run one or more tests (by number) or groups of tests (by name) */
+    for (i = optind; i < argc; ++i) {
+        if (strcmp(argv[i], "all") == 0) {
+            for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+                if (all_tests[j]() != 0)
+                    return EXIT_FAILURE;
+        }
+        else if (isdigit(argv[i][0]) &&
+                 (((j = atoi(argv[i])) >= 0) &&
+                  (j < sizeof(all_tests)/sizeof(all_tests[0])))) {
+            if (all_tests[j]() != 0)
+                return EXIT_FAILURE;
+        }
+        else {
+            fprintf(stderr, "unknown test case %s\n", argv[i]);
+            return EXIT_FAILURE;
+        }
+    }
+
+    return EXIT_SUCCESS;
+}



More information about the Commits mailing list