[Cryptech-Commits] [sw/cryptlib] 01/01: Add EIM HAL.

git at cryptech.is git at cryptech.is
Wed Apr 8 20:39:56 UTC 2015


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

paul at psgd.org pushed a commit to branch master
in repository sw/cryptlib.

commit 7435ac81de2ebe5b312b2435795c4c027d6add75
Author: Paul Selkirk <paul at psgd.org>
Date:   Wed Apr 8 16:38:45 2015 -0400

    Add EIM HAL.
    
    The eim and i2c support are copied from core/platform/novena.
    In future, we should maybe build a library there, and link it here.
---
 GNUmakefile                                        |   2 +-
 src/cryptech_memory_map.h                          | 217 +++++++
 ...ovena_i2c_trng.c => cryptech_novena_eim_trng.c} | 456 ++-----------
 src/cryptech_novena_i2c_trng.c                     | 430 ++-----------
 src/novena-eim.c                                   | 708 +++++++++++++++++++++
 src/novena-eim.h                                   |  52 ++
 src/tc_eim.c                                       | 185 ++++++
 src/tc_eim.h                                       |  50 ++
 src/tc_i2c.c                                       | 331 ++++++++++
 src/tc_i2c.h                                       |  55 ++
 tests/test_trng.py                                 |   2 +-
 11 files changed, 1706 insertions(+), 782 deletions(-)

diff --git a/GNUmakefile b/GNUmakefile
index 9742a8f..e48ee1e 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -12,7 +12,7 @@
 # documentation for details).
 
 ifndef CRYPTECH_HAL
-  CRYPTECH_HAL := src/cryptech_novena_i2c_trng.c
+  CRYPTECH_HAL := src/cryptech_novena_eim_trng.c
 endif
 
 # RNG hack defaults to enabled if we're building the TRNG, disabled
diff --git a/src/cryptech_memory_map.h b/src/cryptech_memory_map.h
new file mode 100644
index 0000000..5cf7f42
--- /dev/null
+++ b/src/cryptech_memory_map.h
@@ -0,0 +1,217 @@
+//======================================================================
+//
+// cryptech_memory_map.h
+// ---------------------
+// The memory map for Cryptech cores.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// Copyright (c) 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.
+//
+//======================================================================
+
+// BASE_ADDR, SEGMENT_SIZE, and ADDR are defined in tc_[eim|i2c].h,
+// which #includes this file.
+
+// default definitions from i2c, because defaults are good
+#ifndef BASE_ADDR
+#define BASE_ADDR               0
+#endif
+#ifndef SEGMENT_SIZE
+#define SEGMENT_SIZE            0x2000
+#endif
+#ifndef ADDR
+#define ADDR(x)                 (x)
+#endif
+
+#ifndef bitsToBytes
+#define bitsToBytes(x)          (x / 8)
+#endif
+
+// Segments.
+#define SEGMENT_OFFSET_GLOBALS  BASE_ADDR + (0 * SEGMENT_SIZE)
+#define SEGMENT_OFFSET_HASHES   BASE_ADDR + (1 * SEGMENT_SIZE)
+#define SEGMENT_OFFSET_RNGS     BASE_ADDR + (2 * SEGMENT_SIZE)
+#define SEGMENT_OFFSET_CIPHERS  BASE_ADDR + (3 * SEGMENT_SIZE)
+
+
+// addresses and codes common to all cores
+#define ADDR_NAME0              ADDR(0x00)
+#define ADDR_NAME1              ADDR(0x01)
+#define ADDR_VERSION            ADDR(0x02)
+
+
+//------------------------------------------------------------------
+// Board segment.
+// Board-level registers and communication channel registers
+//------------------------------------------------------------------
+#define BOARD_CORE_SIZE         ADDR(0x100)
+
+#define BOARD_ADDR_BASE         SEGMENT_OFFSET_GLOBALS + (0 * BOARD_CORE_SIZE)
+#define BOARD_ADDR_NAME0        BOARD_ADDR_BASE + ADDR_NAME0
+#define BOARD_ADDR_NAME1        BOARD_ADDR_BASE + ADDR_NAME1
+#define BOARD_ADDR_VERSION      BOARD_ADDR_BASE + ADDR_VERSION
+#define BOARD_ADDR_DUMMY        BOARD_ADDR_BASE + ADDR(0xFF)
+
+#define COMM_ADDR_BASE          SEGMENT_OFFSET_GLOBALS + (1 * BOARD_CORE_SIZE)
+#define COMM_ADDR_NAME0         COMM_ADDR_BASE + ADDR_NAME0
+#define COMM_ADDR_NAME1         COMM_ADDR_BASE + ADDR_NAME1
+#define COMM_ADDR_VERSION       COMM_ADDR_BASE + ADDR_VERSION
+
+
+//------------------------------------------------------------------
+// Hashes segment.
+//------------------------------------------------------------------
+#define HASH_CORE_SIZE          ADDR(0x100)
+
+// addresses and codes common to all hash cores */
+#define ADDR_CTRL               ADDR(0x8)
+#define CTRL_INIT_CMD           1
+#define CTRL_NEXT_CMD           2
+#define ADDR_STATUS             ADDR(0x9)
+#define STATUS_READY_BIT        1
+#define STATUS_VALID_BIT        2
+#define ADDR_BLOCK              ADDR(0x10)
+#define ADDR_DIGEST             ADDR(0x20)      // except SHA512
+
+// addresses and codes for the specific hash cores.
+#define SHA1_ADDR_BASE          SEGMENT_OFFSET_HASHES + (0 * HASH_CORE_SIZE)
+#define SHA1_ADDR_NAME0         SHA1_ADDR_BASE + ADDR_NAME0
+#define SHA1_ADDR_NAME1         SHA1_ADDR_BASE + ADDR_NAME1
+#define SHA1_ADDR_VERSION       SHA1_ADDR_BASE + ADDR_VERSION
+#define SHA1_ADDR_CTRL          SHA1_ADDR_BASE + ADDR_CTRL
+#define SHA1_ADDR_STATUS        SHA1_ADDR_BASE + ADDR_STATUS
+#define SHA1_ADDR_BLOCK         SHA1_ADDR_BASE + ADDR_BLOCK
+#define SHA1_ADDR_DIGEST        SHA1_ADDR_BASE + ADDR_DIGEST
+#define SHA1_BLOCK_LEN          bitsToBytes(512)
+#define SHA1_LENGTH_LEN         bitsToBytes(64)
+#define SHA1_DIGEST_LEN         bitsToBytes(160)
+
+#define SHA256_ADDR_BASE        SEGMENT_OFFSET_HASHES + (1 * HASH_CORE_SIZE)
+#define SHA256_ADDR_NAME0       SHA256_ADDR_BASE + ADDR_NAME0
+#define SHA256_ADDR_NAME1       SHA256_ADDR_BASE + ADDR_NAME1
+#define SHA256_ADDR_VERSION     SHA256_ADDR_BASE + ADDR_VERSION
+#define SHA256_ADDR_CTRL        SHA256_ADDR_BASE + ADDR_CTRL
+#define SHA256_ADDR_STATUS      SHA256_ADDR_BASE + ADDR_STATUS
+#define SHA256_ADDR_BLOCK       SHA256_ADDR_BASE + ADDR_BLOCK
+#define SHA256_ADDR_DIGEST      SHA256_ADDR_BASE + ADDR_DIGEST
+#define SHA256_BLOCK_LEN        bitsToBytes(512)
+#define SHA256_LENGTH_LEN       bitsToBytes(64)
+#define SHA256_DIGEST_LEN       bitsToBytes(256)
+
+#define SHA512_ADDR_BASE        SEGMENT_OFFSET_HASHES + (2 * HASH_CORE_SIZE)
+#define SHA512_ADDR_NAME0       SHA512_ADDR_BASE + ADDR_NAME0
+#define SHA512_ADDR_NAME1       SHA512_ADDR_BASE + ADDR_NAME1
+#define SHA512_ADDR_VERSION     SHA512_ADDR_BASE + ADDR_VERSION
+#define SHA512_ADDR_CTRL        SHA512_ADDR_BASE + ADDR_CTRL
+#define SHA512_ADDR_STATUS      SHA512_ADDR_BASE + ADDR_STATUS
+#define SHA512_ADDR_BLOCK       SHA512_ADDR_BASE + ADDR_BLOCK
+#define SHA512_ADDR_DIGEST      SHA512_ADDR_BASE + ADDR(0x40)
+#define SHA512_BLOCK_LEN        bitsToBytes(1024)
+#define SHA512_LENGTH_LEN       bitsToBytes(128)
+#define SHA512_224_DIGEST_LEN   bitsToBytes(224)
+#define SHA512_256_DIGEST_LEN   bitsToBytes(256)
+#define SHA384_DIGEST_LEN       bitsToBytes(384)
+#define SHA512_DIGEST_LEN       bitsToBytes(512)
+#define MODE_SHA_512_224        0 << 2
+#define MODE_SHA_512_256        1 << 2
+#define MODE_SHA_384            2 << 2
+#define MODE_SHA_512            3 << 2
+
+
+// -----------------------------------------------------------------
+// TRNG segment.
+// -----------------------------------------------------------------
+#define TRNG_CORE_SIZE          ADDR(0x100)
+
+// addresses and codes for the TRNG cores */
+#define TRNG_ADDR_BASE          SEGMENT_OFFSET_RNGS + (0 * TRNG_CORE_SIZE)
+#define TRNG_ADDR_NAME0         TRNG_ADDR_BASE + ADDR_NAME0
+#define TRNG_ADDR_NAME1         TRNG_ADDR_BASE + ADDR_NAME1
+#define TRNG_ADDR_VERSION       TRNG_ADDR_BASE + ADDR_VERSION
+#define TRNG_ADDR_CTRL          TRNG_ADDR_BASE + ADDR(0x10)
+#define TRNG_CTRL_DISCARD       1
+#define TRNG_CTRL_TEST_MODE     2
+#define TRNG_ADDR_STATUS        TRNG_ADDR_BASE + ADDR(0x11)
+// no status bits defined (yet)
+#define TRNG_ADDR_DELAY         TRNG_ADDR_BASE + ADDR(0x13)
+
+#define ENTROPY1_ADDR_BASE      SEGMENT_OFFSET_RNGS + (5 * TRNG_CORE_SIZE)
+#define ENTROPY1_ADDR_NAME0     ENTROPY1_ADDR_BASE + ADDR_NAME0
+#define ENTROPY1_ADDR_NAME1     ENTROPY1_ADDR_BASE + ADDR_NAME1
+#define ENTROPY1_ADDR_VERSION   ENTROPY1_ADDR_BASE + ADDR_VERSION
+#define ENTROPY1_ADDR_CTRL      ENTROPY1_ADDR_BASE + ADDR(0x10)
+#define ENTROPY1_CTRL_ENABLE    1
+#define ENTROPY1_ADDR_STATUS    ENTROPY1_ADDR_BASE + ADDR(0x11)
+#define ENTROPY1_STATUS_VALID   1
+#define ENTROPY1_ADDR_ENTROPY   ENTROPY1_ADDR_BASE + ADDR(0x20)
+#define ENTROPY1_ADDR_DELTA     ENTROPY1_ADDR_BASE + ADDR(0x30)
+
+#define ENTROPY2_ADDR_BASE      SEGMENT_OFFSET_RNGS + (6 * TRNG_CORE_SIZE)
+#define ENTROPY2_ADDR_NAME0     ENTROPY2_ADDR_BASE + ADDR_NAME0
+#define ENTROPY2_ADDR_NAME1     ENTROPY2_ADDR_BASE + ADDR_NAME1
+#define ENTROPY2_ADDR_VERSION   ENTROPY2_ADDR_BASE + ADDR_VERSION
+#define ENTROPY2_ADDR_CTRL      ENTROPY2_ADDR_BASE + ADDR(0x10)
+#define ENTROPY2_CTRL_ENABLE    1
+#define ENTROPY2_ADDR_STATUS    ENTROPY2_ADDR_BASE + ADDR(0x11)
+#define ENTROPY2_STATUS_VALID   1
+#define ENTROPY2_ADDR_OPA       ENTROPY2_ADDR_BASE + ADDR(0x18)
+#define ENTROPY2_ADDR_OPB       ENTROPY2_ADDR_BASE + ADDR(0x19)
+#define ENTROPY2_ADDR_ENTROPY   ENTROPY2_ADDR_BASE + ADDR(0x20)
+#define ENTROPY2_ADDR_RAW       ENTROPY2_ADDR_BASE + ADDR(0x21)
+#define ENTROPY2_ADDR_ROSC      ENTROPY2_ADDR_BASE + ADDR(0x22)
+
+#define MIXER_ADDR_BASE         SEGMENT_OFFSET_RNGS + (0x0a * TRNG_CORE_SIZE)
+#define MIXER_ADDR_NAME0        MIXER_ADDR_BASE + ADDR_NAME0
+#define MIXER_ADDR_NAME1        MIXER_ADDR_BASE + ADDR_NAME1
+#define MIXER_ADDR_VERSION      MIXER_ADDR_BASE + ADDR_VERSION
+#define MIXER_ADDR_CTRL         MIXER_ADDR_BASE + ADDR(0x10)
+#define MIXER_CTRL_ENABLE       1
+#define MIXER_CTRL_RESTART      2
+#define MIXER_ADDR_STATUS       MIXER_ADDR_BASE + ADDR(0x11)
+// no status bits defined (yet)
+#define MIXER_ADDR_TIMEOUT      MIXER_ADDR_BASE + ADDR(0x20)
+
+#define CSPRNG_ADDR_BASE        SEGMENT_OFFSET_RNGS + (0x0b * TRNG_CORE_SIZE)
+#define CSPRNG_ADDR_NAME0       CSPRNG_ADDR_BASE + ADDR_NAME0
+#define CSPRNG_ADDR_NAME1       CSPRNG_ADDR_BASE + ADDR_NAME1
+#define CSPRNG_ADDR_VERSION     CSPRNG_ADDR_BASE + ADDR_VERSION
+#define CSPRNG_ADDR_CTRL        CSPRNG_ADDR_BASE + ADDR(0x10)
+#define CSPRNG_CTRL_ENABLE      1
+#define CSPRNG_CTRL_SEED        2
+#define CSPRNG_ADDR_STATUS      CSPRNG_ADDR_BASE + ADDR(0x11)
+#define CSPRNG_STATUS_VALID     1
+#define CSPRNG_ADDR_RANDOM      CSPRNG_ADDR_BASE + ADDR(0x20)
+#define CSPRNG_ADDR_NROUNDS     CSPRNG_ADDR_BASE + ADDR(0x40)
+#define CSPRNG_ADDR_NBLOCKS_LO  CSPRNG_ADDR_BASE + ADDR(0x41)
+#define CSPRNG_ADDR_NBLOCKS_HI  CSPRNG_ADDR_BASE + ADDR(0x42)
+
+//======================================================================
+// EOF cryptech_memory_map.h
+//======================================================================
diff --git a/src/cryptech_novena_i2c_trng.c b/src/cryptech_novena_eim_trng.c
similarity index 57%
copy from src/cryptech_novena_i2c_trng.c
copy to src/cryptech_novena_eim_trng.c
index 5877acc..f959705 100644
--- a/src/cryptech_novena_i2c_trng.c
+++ b/src/cryptech_novena_eim_trng.c
@@ -1,20 +1,13 @@
 /* 
- * cryptech_novena_i2c_trng.c
- * ------------------------------
+ * cryptech_novena_eim_trng.c
+ * --------------------------
  *
- * This is an early prototype Hardware Adaption Layer (HAL) for using
- * Cryptlib with the Cryptech project's FGPA cores over an I2C bus on
- * the Novena PVT1 development board using the "coretest" byte stream
- * protocol.  This is compatible with the test/novena_trng FPGA build.
+ * This is a prototype Hardware Adaption Layer (HAL) for using
+ * Cryptlib with the Cryptech project's FGPA cores over an EIM bus on
+ * the Novena PVT1 development board.
  *
- * Well, except that apparently cryptlib doesn't like it when we just
- * provide a TRNG, so try also adding all the code for the hash cores.
- *
- * The communication channel used here is not suitable for production
- * use, this is just a prototype.
- * 
  * Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein
- * Copyright (c) 2014, SUNET
+ * Copyright (c) 2014-2015, SUNET
  * 
  * Redistribution and use in source and binary forms, with or 
  * without modification, are permitted provided that the following 
@@ -53,6 +46,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <stdint.h>
 
 #if defined( INC_ALL )
   #include "crypt.h"
@@ -64,87 +58,14 @@
   #include "device/hardware.h"
 #endif /* Compiler-specific includes */
 
-/*
- * I2C_SLAVE comes from /usr/include/linux/i2c-dev.h, but if we
- * include that we won't be able to compile this except on Linux.  It
- * won't *run* anywhere but on Linux, but it's useful to be able to do
- * compilation tests on other platforms, eg, with Clang, so for now we
- * take the small risk that this one magic constant might change.
- */
-
-#define I2C_SLAVE       0x0703
+#include "tc_eim.h"
 
+/* XXX This is gross, but it saves us from having to build a library. */
+#include "novena-eim.c"
+#include "tc_eim.c"
 
 #ifdef USE_HARDWARE
 
-/*
- * I2C-related parameters, copied from hash_tester.c
- */
-
-/* I2C configuration */
-#define I2C_DEV   "/dev/i2c-2"
-#define I2C_ADDR  0x0f
-
-/* Command codes */
-#define SOC       0x55
-#define EOC       0xaa
-#define READ_CMD  0x10
-#define WRITE_CMD 0x11
-#define RESET_CMD 0x01
-
-/* Response codes */
-#define SOR       0xaa
-#define EOR       0x55
-#define READ_OK   0x7f
-#define WRITE_OK  0x7e
-#define RESET_OK  0x7d
-#define UNKNOWN   0xfe
-#define ERROR     0xfd
-
-/* Addresses and codes common to all cores */
-#define ADDR_NAME0              0x00
-#define ADDR_NAME1              0x01
-#define ADDR_VERSION            0x02
-#define ADDR_CTRL               0x08
-#define CTRL_INIT_CMD           1
-#define CTRL_NEXT_CMD           2
-#define ADDR_STATUS             0x09
-#define STATUS_READY_BIT        1
-#define STATUS_VALID_BIT        2
-
-/*
- * Addresses and codes for the specific hash cores.
- * Lengths here are in bytes (not bits, not 32-bit words).
- */
-
-#define SHA1_ADDR_PREFIX        0x10
-#define SHA1_ADDR_BLOCK         0x10
-#define SHA1_BLOCK_LEN          bitsToBytes(512)
-#define	SHA1_LENGTH_LEN		bitsToBytes(64)
-#define SHA1_ADDR_DIGEST        0x20
-#define SHA1_DIGEST_LEN         bitsToBytes(160)
-
-#define SHA256_ADDR_PREFIX      0x20
-#define SHA256_ADDR_BLOCK       0x10
-#define SHA256_BLOCK_LEN        bitsToBytes(512)
-#define	SHA256_LENGTH_LEN	bitsToBytes(64)
-#define SHA256_ADDR_DIGEST      0x20
-#define SHA256_DIGEST_LEN       bitsToBytes(256)
-
-#define SHA512_ADDR_PREFIX      0x30
-#define SHA512_CTRL_MODE_LOW    2
-#define SHA512_CTRL_MODE_HIGH   3
-#define SHA512_ADDR_BLOCK       0x10
-#define SHA512_BLOCK_LEN        bitsToBytes(1024)
-#define	SHA512_LENGTH_LEN	bitsToBytes(128)
-#define SHA512_ADDR_DIGEST      0x40
-#define SHA384_DIGEST_LEN       bitsToBytes(384)
-#define SHA512_DIGEST_LEN       bitsToBytes(512)
-#define MODE_SHA_512_224        (0 << SHA512_CTRL_MODE_LOW)
-#define MODE_SHA_512_256        (1 << SHA512_CTRL_MODE_LOW)
-#define MODE_SHA_384            (2 << SHA512_CTRL_MODE_LOW)
-#define MODE_SHA_512            (3 << SHA512_CTRL_MODE_LOW)
-
 /* Longest digest block we support at the moment */
 #define MAX_BLOCK_LEN           SHA512_BLOCK_LEN
 
@@ -158,251 +79,7 @@ typedef struct {
   unsigned block_count;                 /* Blocks sent */
 } hash_state_t;
 
-/*
- * Address for reading 32 bits of entropy from the noise board.
- * TRNG_VALID is nonzero if valid random bits are available.
- */
-
-#define	TRNG_PREFIX		0x0b
-#define	TRNG_DATA		0x20
-#define	TRNG_VALID		0x11
-
-static int i2cfd = -1;
-static int debug = 0;
-
-/*
- * I2C low-level code
- */
-
-static int i2c_open(void)
-{
-  if (i2cfd >= 0)
-    return 1;
-
-  i2cfd = open(I2C_DEV, O_RDWR);
-
-  if (i2cfd < 0) {
-    perror("Unable to open " I2C_DEV);
-    i2cfd = -1;
-    return 0;
-  }
-
-  if (ioctl(i2cfd, I2C_SLAVE, I2C_ADDR) < 0) {
-    perror("Unable to set i2c slave device");
-    return 0;
-  }
-
-  if (debug)
-    fprintf(stderr, "[ Opened %s, fd %d ]\n", I2C_DEV, i2cfd);
-
-  return 1;
-}
-
-static int i2c_write_bytes(const unsigned char *buf, const size_t len)
-{
-  if (debug) {
-    int i;
-    fprintf(stderr, "write [");
-    for (i = 0; i < len; ++i)
-      fprintf(stderr, " %02x", buf[i]);
-    fprintf(stderr, " ]\n");
-  }
-
-  if (!i2c_open())
-    return 0;
-
-  if (write(i2cfd, buf, len) != len) {
-    perror("i2c write failed");
-    return 0;
-  }
-
-  return 1;
-}
-
-
-static int i2c_read_byte(unsigned char *b)
-{
-  /*
-   * read() on the i2c device only returns one byte at a time,
-   * and we need to parse the response one byte at a time anyway.
-   */
-
-  if (!i2c_open())
-    return 0;
-
-  if (read(i2cfd, b, 1) != 1) {
-    perror("i2c read failed");
-    return 0;
-  }
-
-  return 1;
-}
-
-static int i2c_send_write_cmd(const unsigned char addr0, const unsigned char addr1, const unsigned char data[])
-{
-  unsigned char buf[9];
-
-  buf[0] = SOC;
-  buf[1] = WRITE_CMD;
-  buf[2] = addr0;
-  buf[3] = addr1;
-  buf[4] = data[0];
-  buf[5] = data[1];
-  buf[6] = data[2];
-  buf[7] = data[3];
-  buf[8] = EOC;
-
-  return i2c_write_bytes(buf, sizeof(buf));
-}
-
-static int i2c_send_read_cmd(const unsigned char addr0, const unsigned char addr1)
-{
-  unsigned char buf[5];
-
-  buf[0] = SOC;
-  buf[1] = READ_CMD;
-  buf[2] = addr0;
-  buf[3] = addr1;
-  buf[4] = EOC;
-
-  return i2c_write_bytes(buf, sizeof(buf));
-}
-
-static int i2c_get_resp(unsigned char *buf, const size_t length)
-{
-  int i, len = length;
-
-  for (i = 0; i < len; ++i) {
-    assert(len <= length);      /* Paranoia */
-
-    if (!i2c_read_byte(&buf[i]))
-      return 0;
-
-    switch (i) {                /* Special handling for certain positions in response */
-
-    case 0:
-      if (buf[i] == SOR)        /* Start of record (we hope) */
-        continue;
-      fprintf(stderr, "Lost sync: expected 0x%02x (SOR), got 0x%02x\n", SOR, buf[0]);
-      return 0;
-
-    case 1:                     /* Response code */
-      switch (buf[i]) {
-      case READ_OK:
-        len = 9;
-        continue;
-      case WRITE_OK:
-        len = 5;
-        continue;
-      case RESET_OK:
-        len = 3;
-        continue;
-      case ERROR:
-      case UNKNOWN:
-        len = 4;
-        continue;
-      default:
-        fprintf(stderr, "Lost sync: unknown response code 0x%02x\n", buf[i]);
-        return 0;
-      }
-    }
-  }
-
-  if (debug) {
-    fprintf(stderr, "read  [");
-    for (i = 0; i < len; ++i)
-      fprintf(stderr, " %02x", buf[i]);
-    fprintf(stderr, " ]\n");
-  }
-
-  return 1;
-}
-
-static int i2c_check_expected(const unsigned char buf[], const int i, const unsigned char expected)
-{
-  if (buf[i] == expected)
-    return 1;
-  fprintf(stderr, "Response byte %d: expected 0x%02x, got 0x%02x\n", i, expected, buf[i]);
-  return 0;
-}
-
-
-static int i2c_write(const unsigned char addr0, const unsigned char addr1, const unsigned char data[])
-{
-  unsigned char buf[5];
-
-  if (!i2c_send_write_cmd(addr0, addr1, data) ||
-      !i2c_get_resp(buf, sizeof(buf))         ||
-      !i2c_check_expected(buf, 0, SOR)        ||
-      !i2c_check_expected(buf, 1, WRITE_OK)   ||
-      !i2c_check_expected(buf, 2, addr0)      ||
-      !i2c_check_expected(buf, 3, addr1)      ||
-      !i2c_check_expected(buf, 4, EOR))
-    return 0;
-
-  return 1;
-}
-
-static int i2c_read(const unsigned char addr0, const unsigned char addr1, unsigned char data[])
-{
-  unsigned char buf[9];
-
-  if (!i2c_send_read_cmd(addr0, addr1)     ||
-      !i2c_get_resp(buf, sizeof(buf))      ||
-      !i2c_check_expected(buf, 0, SOR)     ||
-      !i2c_check_expected(buf, 1, READ_OK) ||
-      !i2c_check_expected(buf, 2, addr0)   ||
-      !i2c_check_expected(buf, 3, addr1)   ||
-      !i2c_check_expected(buf, 8, EOR))
-    return 0;
-
-  data[0] = buf[4];
-  data[1] = buf[5];
-  data[2] = buf[6];
-  data[3] = buf[7];
-  return 1;
-}
-
-static int i2c_ctrl(const unsigned char addr0, const unsigned char ctrl_cmd)
-{
-  unsigned char data[4];
-  memset(data, 0, sizeof(data));
-  data[3] = ctrl_cmd;
-  return i2c_write(addr0, ADDR_CTRL, data);
-}
-
-static int i2c_wait(const unsigned char addr0, const unsigned char status)
-{
-  unsigned char buf[9];
-
-  do {
-    if (!i2c_send_read_cmd(addr0, ADDR_STATUS))
-      return 0;
-    if (!i2c_get_resp(buf, sizeof(buf)))
-      return 0;
-    if (buf[1] != READ_OK)
-      return 0;
-  } while ((buf[7] & status) != status);
-
-  if (debug)
-    fprintf(stderr, "[ Done waiting ]\n");
-
-  return 1;
-}
-
-static int i2c_wait_ready(const unsigned char addr0)
-{
-  if (debug)
-    fprintf(stderr, "[ Waiting for ready ]\n");
-  return i2c_wait(addr0, STATUS_READY_BIT);
-}
-
-static int i2c_wait_valid(const unsigned char addr0)
-{
-  if (debug)
-    fprintf(stderr, "[ Waiting for valid ]\n");
-  return i2c_wait(addr0, STATUS_VALID_BIT);
-}
+int debug = 0;
 
 /****************************************************************************
  *                                                                          *
@@ -414,47 +91,44 @@ static int i2c_wait_valid(const unsigned char addr0)
  * Send one block to a core.
  */
 
-static int hash_write_block(const unsigned char addr_prefix,
-                            const unsigned char addr_block,
-                            const unsigned char ctrl_mode,
+static int hash_write_block(const off_t offset,
+                            const uint8_t ctrl_mode,
                             const hash_state_t *state)
 {
-  unsigned char ctrl_cmd;
-  int i;
+  uint8_t ctrl_cmd[4] = { 0 };
+  off_t base = offset & ~(0x3ff);
 
   assert(state != NULL && state->block_length % 4 == 0);
 
-  for (i = 0; i + 3 < state->block_length; i += 4)
-    if (!i2c_write(addr_prefix, addr_block + i/4, state->block + i))
-      return 0;
+  if (tc_write(offset, state->block, state->block_length) != 0)
+    return CRYPT_ERROR_FAILED;
 
-  ctrl_cmd = state->block_count == 0 ? CTRL_INIT_CMD : CTRL_NEXT_CMD;
+  ctrl_cmd[3] = (state->block_count == 0 ? CTRL_INIT_CMD : CTRL_NEXT_CMD) | ctrl_mode;
 
   if (debug)
     fprintf(stderr, "[ %s ]\n", state->block_count == 0 ? "init" : "next");
 
-  return i2c_ctrl(addr_prefix, ctrl_cmd|ctrl_mode) && i2c_wait_ready(addr_prefix);
+  return
+    tc_write(base + ADDR_CTRL, ctrl_cmd, 4) ||
+    tc_wait_ready(base + ADDR_STATUS);
 }
 
 /*
  * Read hash result from core.
  */
 
-static int hash_read_digest(const unsigned char addr_prefix, const unsigned char addr_digest,
-                            unsigned char *digest, const size_t digest_length)
+static int hash_read_digest(const off_t offset,
+                            unsigned char *digest,
+                            const size_t digest_length)
 {
-  int i;
-
   assert(digest_length % 4 == 0);
 
-  if (!i2c_wait_valid(addr_prefix))
-    return 0;
-
-  for (i = 0; i + 3 < digest_length; i += 4)
-    if (!i2c_read(addr_prefix, addr_digest + i/4, digest + i))
-      return 0;
+  /* Technically, we should poll the status register for the "valid" bit, but
+   * hash_write_block() has already polled for the "ready" bit, and we know
+   * that the sha cores always set valid one clock cycle before ready.
+   */
 
-  return 1;
+  return tc_read(offset, digest, digest_length);
 }
 
 /****************************************************************************
@@ -465,18 +139,8 @@ static int hash_read_digest(const unsigned char addr_prefix, const unsigned char
 
 /*
  * First attempt at reading random data from the Novena.
- *
- * In theory, we should wait for TRNG_VALID before reading random
- * data, but as long as this is running over I2C we're going to be so
- * slow that there's no point, and checking would just make us slower.
- *
- * If the TRNG isn't installed we need to return failure to our
- * caller.  At least with the current I2C coretest interface, coretest
- * signals this (deliberately?) by returning all zeros.
  */
 
-#define WAIT_FOR_TRNG_VALID	0
-
 static int readRandom(void *buffer, const int length)
 {
   unsigned char temp[4], *buf = buffer;
@@ -491,27 +155,15 @@ static int readRandom(void *buffer, const int length)
 
   for (i = 0; i < length; i += 4) {
 
-#if WAIT_FOR_TRNG_VALID
-    if (!i2c_wait_valid(TRNG_PREFIX)) {
-      fprintf(stderr, "[ i2c_wait_valid(TRNG_PREFIX) failed ]\n");
-      return 0;
-    }
-    do {
-      if (!i2c_read(TRNG_PREFIX, TRNG_VALID, temp)) {
-        fprintf(stderr, "[ i2c_read(TRNG_VALID) failed ]\n");
-        return 0;
-      }
-    } while (!temp[3]);
-    if (!i2c_wait_valid(TRNG_PREFIX)) {
-      fprintf(stderr, "[ i2c_wait_valid(TRNG_PREFIX) failed ]\n");
-      return 0;
+    if (tc_wait_ready(CSPRNG_ADDR_STATUS) != 0) {
+      fprintf(stderr, "[ tc_wait_valid(CSPRNG_ADDR_STATUS) failed ]\n");
+      return CRYPT_ERROR_FAILED;
     }
-#endif  /* WAIT_FOR_TRNG_VALID */
 
     last = (length - i) < 4;
-    if (!i2c_read(TRNG_PREFIX, TRNG_DATA, (last ? temp : (buf + i)))) {
-      fprintf(stderr, "[ i2c_read(TRNG_DATA) failed ]\n");
-      return 0;
+    if (tc_read(CSPRNG_ADDR_RANDOM, (last ? temp : (buf + i)), 4) != 0) {
+      fprintf(stderr, "[ tc_read(CSPRNG_ADDR_RANDOM) failed ]\n");
+      return CRYPT_ERROR_FAILED;
     }
     if (last) {
       for (; i < length; i++)
@@ -521,10 +173,10 @@ static int readRandom(void *buffer, const int length)
 
   for (i = 0, buf = buffer; i < length; i++, buf++)
     if (*buf != 0)
-      return 1;
+      return CRYPT_OK;
 
   fprintf(stderr, "[ \"Random\" data all zeros, guess TRNG is not installed ]\n");
-  return 0;
+  return CRYPT_ERROR_FAILED;
 }
 
 /****************************************************************************
@@ -562,9 +214,14 @@ static int hashGetInfo(const CAPABILITY_INFO_TYPE type,
  * with a few parameters which we handle via closures below.
  */
 
-static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int length,
-                  const size_t block_length, const unsigned char addr_prefix, const unsigned char addr_block,
-                  const size_t digest_length, const unsigned char addr_digest, const unsigned char ctrl_mode,
+static int doHash(CONTEXT_INFO *contextInfoPtr,
+                  const unsigned char *buffer,
+                  int length,
+                  const size_t block_length,
+                  const off_t addr_block,
+                  const size_t digest_length,
+                  const off_t addr_digest,
+                  const unsigned char ctrl_mode,
                   const size_t length_length)
 {
   hash_state_t *state = NULL;
@@ -605,7 +262,7 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int
       state->block_used = 0;
       length -= n;
       p += n;
-      if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state))
+      if (hash_write_block(addr_block, ctrl_mode, state) != 0)
         return CRYPT_ERROR_FAILED;
       state->block_count++;
     }
@@ -642,7 +299,7 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int
                 (unsigned long) length, (unsigned long) state->block_used, (unsigned long) n, state->msg_length_low);
       if (n > 0)
         memset(state->block + state->block_used, 0, n);
-      if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state))
+      if (hash_write_block(addr_block, ctrl_mode, state) != 0)
         return CRYPT_ERROR_FAILED;
       state->block_count++;
       state->block_used = 0;
@@ -667,14 +324,14 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int
     }
 
     /* Push final block */
-    if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state))
+    if (hash_write_block(addr_block, ctrl_mode, state) != 0)
       return CRYPT_ERROR_FAILED;
     state->block_count++;
 
     /* All data pushed to core, now we just need to read back the result */
 
     assert(digest_length <= sizeof(contextInfoPtr->ctxHash->hash));
-    if (!hash_read_digest(addr_prefix, addr_digest, contextInfoPtr->ctxHash->hash, digest_length))
+    if (hash_read_digest(addr_digest, contextInfoPtr->ctxHash->hash, digest_length) != 0)
       return CRYPT_ERROR_FAILED;
   }
 
@@ -697,7 +354,7 @@ static int sha1SelfTest(void)
 static int sha1Hash(CONTEXT_INFO *contextInfoPtr, unsigned char *buffer, int length)
 {
   return doHash(contextInfoPtr, buffer, length,
-                SHA1_BLOCK_LEN, SHA1_ADDR_PREFIX, SHA1_ADDR_BLOCK,
+                SHA1_BLOCK_LEN, SHA1_ADDR_BLOCK,
                 SHA1_DIGEST_LEN, SHA1_ADDR_DIGEST, 0, SHA1_LENGTH_LEN);
 }
 
@@ -722,18 +379,18 @@ static int sha2Hash(CONTEXT_INFO *contextInfoPtr, unsigned char *buffer, int len
 
   case bitsToBytes(256):
     return doHash(contextInfoPtr, buffer, length,
-                  SHA256_BLOCK_LEN, SHA256_ADDR_PREFIX, SHA256_ADDR_BLOCK,
+                  SHA256_BLOCK_LEN, SHA256_ADDR_BLOCK,
                   SHA256_DIGEST_LEN, SHA256_ADDR_DIGEST, 0, SHA256_LENGTH_LEN);
 
   case bitsToBytes(384):
     return doHash(contextInfoPtr, buffer, length,
-                  SHA512_BLOCK_LEN, SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK,
+                  SHA512_BLOCK_LEN, SHA512_ADDR_BLOCK,
                   SHA384_DIGEST_LEN, SHA512_ADDR_DIGEST, MODE_SHA_384,
                   SHA512_LENGTH_LEN);
 
   case bitsToBytes(512):
     return doHash(contextInfoPtr, buffer, length,
-                  SHA512_BLOCK_LEN, SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK,
+                  SHA512_BLOCK_LEN, SHA512_ADDR_BLOCK,
                   SHA512_DIGEST_LEN, SHA512_ADDR_DIGEST, MODE_SHA_512,
                   SHA512_LENGTH_LEN);
 
@@ -837,10 +494,7 @@ int hwGetRandom(void *buffer, const int length)
 
   REQUIRES(length >= 1 && length < MAX_INTLENGTH);
 
-  if (readRandom(buffer, length))
-    return CRYPT_OK;
-  else
-    return CRYPT_ERROR_RANDOM;
+  return readRandom(buffer, length);
 }
 
 /*
diff --git a/src/cryptech_novena_i2c_trng.c b/src/cryptech_novena_i2c_trng.c
index 5877acc..92f851a 100644
--- a/src/cryptech_novena_i2c_trng.c
+++ b/src/cryptech_novena_i2c_trng.c
@@ -1,6 +1,6 @@
 /* 
  * cryptech_novena_i2c_trng.c
- * ------------------------------
+ * --------------------------
  *
  * This is an early prototype Hardware Adaption Layer (HAL) for using
  * Cryptlib with the Cryptech project's FGPA cores over an I2C bus on
@@ -14,7 +14,7 @@
  * use, this is just a prototype.
  * 
  * Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein
- * Copyright (c) 2014, SUNET
+ * Copyright (c) 2014-2015, SUNET
  * 
  * Redistribution and use in source and binary forms, with or 
  * without modification, are permitted provided that the following 
@@ -53,6 +53,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <stdint.h>
 
 #if defined( INC_ALL )
   #include "crypt.h"
@@ -64,87 +65,13 @@
   #include "device/hardware.h"
 #endif /* Compiler-specific includes */
 
-/*
- * I2C_SLAVE comes from /usr/include/linux/i2c-dev.h, but if we
- * include that we won't be able to compile this except on Linux.  It
- * won't *run* anywhere but on Linux, but it's useful to be able to do
- * compilation tests on other platforms, eg, with Clang, so for now we
- * take the small risk that this one magic constant might change.
- */
-
-#define I2C_SLAVE       0x0703
+#include "tc_i2c.h"
 
+/* XXX This is gross, but it saves us from having to build a library. */
+#include "tc_i2c.c"
 
 #ifdef USE_HARDWARE
 
-/*
- * I2C-related parameters, copied from hash_tester.c
- */
-
-/* I2C configuration */
-#define I2C_DEV   "/dev/i2c-2"
-#define I2C_ADDR  0x0f
-
-/* Command codes */
-#define SOC       0x55
-#define EOC       0xaa
-#define READ_CMD  0x10
-#define WRITE_CMD 0x11
-#define RESET_CMD 0x01
-
-/* Response codes */
-#define SOR       0xaa
-#define EOR       0x55
-#define READ_OK   0x7f
-#define WRITE_OK  0x7e
-#define RESET_OK  0x7d
-#define UNKNOWN   0xfe
-#define ERROR     0xfd
-
-/* Addresses and codes common to all cores */
-#define ADDR_NAME0              0x00
-#define ADDR_NAME1              0x01
-#define ADDR_VERSION            0x02
-#define ADDR_CTRL               0x08
-#define CTRL_INIT_CMD           1
-#define CTRL_NEXT_CMD           2
-#define ADDR_STATUS             0x09
-#define STATUS_READY_BIT        1
-#define STATUS_VALID_BIT        2
-
-/*
- * Addresses and codes for the specific hash cores.
- * Lengths here are in bytes (not bits, not 32-bit words).
- */
-
-#define SHA1_ADDR_PREFIX        0x10
-#define SHA1_ADDR_BLOCK         0x10
-#define SHA1_BLOCK_LEN          bitsToBytes(512)
-#define	SHA1_LENGTH_LEN		bitsToBytes(64)
-#define SHA1_ADDR_DIGEST        0x20
-#define SHA1_DIGEST_LEN         bitsToBytes(160)
-
-#define SHA256_ADDR_PREFIX      0x20
-#define SHA256_ADDR_BLOCK       0x10
-#define SHA256_BLOCK_LEN        bitsToBytes(512)
-#define	SHA256_LENGTH_LEN	bitsToBytes(64)
-#define SHA256_ADDR_DIGEST      0x20
-#define SHA256_DIGEST_LEN       bitsToBytes(256)
-
-#define SHA512_ADDR_PREFIX      0x30
-#define SHA512_CTRL_MODE_LOW    2
-#define SHA512_CTRL_MODE_HIGH   3
-#define SHA512_ADDR_BLOCK       0x10
-#define SHA512_BLOCK_LEN        bitsToBytes(1024)
-#define	SHA512_LENGTH_LEN	bitsToBytes(128)
-#define SHA512_ADDR_DIGEST      0x40
-#define SHA384_DIGEST_LEN       bitsToBytes(384)
-#define SHA512_DIGEST_LEN       bitsToBytes(512)
-#define MODE_SHA_512_224        (0 << SHA512_CTRL_MODE_LOW)
-#define MODE_SHA_512_256        (1 << SHA512_CTRL_MODE_LOW)
-#define MODE_SHA_384            (2 << SHA512_CTRL_MODE_LOW)
-#define MODE_SHA_512            (3 << SHA512_CTRL_MODE_LOW)
-
 /* Longest digest block we support at the moment */
 #define MAX_BLOCK_LEN           SHA512_BLOCK_LEN
 
@@ -158,251 +85,7 @@ typedef struct {
   unsigned block_count;                 /* Blocks sent */
 } hash_state_t;
 
-/*
- * Address for reading 32 bits of entropy from the noise board.
- * TRNG_VALID is nonzero if valid random bits are available.
- */
-
-#define	TRNG_PREFIX		0x0b
-#define	TRNG_DATA		0x20
-#define	TRNG_VALID		0x11
-
-static int i2cfd = -1;
-static int debug = 0;
-
-/*
- * I2C low-level code
- */
-
-static int i2c_open(void)
-{
-  if (i2cfd >= 0)
-    return 1;
-
-  i2cfd = open(I2C_DEV, O_RDWR);
-
-  if (i2cfd < 0) {
-    perror("Unable to open " I2C_DEV);
-    i2cfd = -1;
-    return 0;
-  }
-
-  if (ioctl(i2cfd, I2C_SLAVE, I2C_ADDR) < 0) {
-    perror("Unable to set i2c slave device");
-    return 0;
-  }
-
-  if (debug)
-    fprintf(stderr, "[ Opened %s, fd %d ]\n", I2C_DEV, i2cfd);
-
-  return 1;
-}
-
-static int i2c_write_bytes(const unsigned char *buf, const size_t len)
-{
-  if (debug) {
-    int i;
-    fprintf(stderr, "write [");
-    for (i = 0; i < len; ++i)
-      fprintf(stderr, " %02x", buf[i]);
-    fprintf(stderr, " ]\n");
-  }
-
-  if (!i2c_open())
-    return 0;
-
-  if (write(i2cfd, buf, len) != len) {
-    perror("i2c write failed");
-    return 0;
-  }
-
-  return 1;
-}
-
-
-static int i2c_read_byte(unsigned char *b)
-{
-  /*
-   * read() on the i2c device only returns one byte at a time,
-   * and we need to parse the response one byte at a time anyway.
-   */
-
-  if (!i2c_open())
-    return 0;
-
-  if (read(i2cfd, b, 1) != 1) {
-    perror("i2c read failed");
-    return 0;
-  }
-
-  return 1;
-}
-
-static int i2c_send_write_cmd(const unsigned char addr0, const unsigned char addr1, const unsigned char data[])
-{
-  unsigned char buf[9];
-
-  buf[0] = SOC;
-  buf[1] = WRITE_CMD;
-  buf[2] = addr0;
-  buf[3] = addr1;
-  buf[4] = data[0];
-  buf[5] = data[1];
-  buf[6] = data[2];
-  buf[7] = data[3];
-  buf[8] = EOC;
-
-  return i2c_write_bytes(buf, sizeof(buf));
-}
-
-static int i2c_send_read_cmd(const unsigned char addr0, const unsigned char addr1)
-{
-  unsigned char buf[5];
-
-  buf[0] = SOC;
-  buf[1] = READ_CMD;
-  buf[2] = addr0;
-  buf[3] = addr1;
-  buf[4] = EOC;
-
-  return i2c_write_bytes(buf, sizeof(buf));
-}
-
-static int i2c_get_resp(unsigned char *buf, const size_t length)
-{
-  int i, len = length;
-
-  for (i = 0; i < len; ++i) {
-    assert(len <= length);      /* Paranoia */
-
-    if (!i2c_read_byte(&buf[i]))
-      return 0;
-
-    switch (i) {                /* Special handling for certain positions in response */
-
-    case 0:
-      if (buf[i] == SOR)        /* Start of record (we hope) */
-        continue;
-      fprintf(stderr, "Lost sync: expected 0x%02x (SOR), got 0x%02x\n", SOR, buf[0]);
-      return 0;
-
-    case 1:                     /* Response code */
-      switch (buf[i]) {
-      case READ_OK:
-        len = 9;
-        continue;
-      case WRITE_OK:
-        len = 5;
-        continue;
-      case RESET_OK:
-        len = 3;
-        continue;
-      case ERROR:
-      case UNKNOWN:
-        len = 4;
-        continue;
-      default:
-        fprintf(stderr, "Lost sync: unknown response code 0x%02x\n", buf[i]);
-        return 0;
-      }
-    }
-  }
-
-  if (debug) {
-    fprintf(stderr, "read  [");
-    for (i = 0; i < len; ++i)
-      fprintf(stderr, " %02x", buf[i]);
-    fprintf(stderr, " ]\n");
-  }
-
-  return 1;
-}
-
-static int i2c_check_expected(const unsigned char buf[], const int i, const unsigned char expected)
-{
-  if (buf[i] == expected)
-    return 1;
-  fprintf(stderr, "Response byte %d: expected 0x%02x, got 0x%02x\n", i, expected, buf[i]);
-  return 0;
-}
-
-
-static int i2c_write(const unsigned char addr0, const unsigned char addr1, const unsigned char data[])
-{
-  unsigned char buf[5];
-
-  if (!i2c_send_write_cmd(addr0, addr1, data) ||
-      !i2c_get_resp(buf, sizeof(buf))         ||
-      !i2c_check_expected(buf, 0, SOR)        ||
-      !i2c_check_expected(buf, 1, WRITE_OK)   ||
-      !i2c_check_expected(buf, 2, addr0)      ||
-      !i2c_check_expected(buf, 3, addr1)      ||
-      !i2c_check_expected(buf, 4, EOR))
-    return 0;
-
-  return 1;
-}
-
-static int i2c_read(const unsigned char addr0, const unsigned char addr1, unsigned char data[])
-{
-  unsigned char buf[9];
-
-  if (!i2c_send_read_cmd(addr0, addr1)     ||
-      !i2c_get_resp(buf, sizeof(buf))      ||
-      !i2c_check_expected(buf, 0, SOR)     ||
-      !i2c_check_expected(buf, 1, READ_OK) ||
-      !i2c_check_expected(buf, 2, addr0)   ||
-      !i2c_check_expected(buf, 3, addr1)   ||
-      !i2c_check_expected(buf, 8, EOR))
-    return 0;
-
-  data[0] = buf[4];
-  data[1] = buf[5];
-  data[2] = buf[6];
-  data[3] = buf[7];
-  return 1;
-}
-
-static int i2c_ctrl(const unsigned char addr0, const unsigned char ctrl_cmd)
-{
-  unsigned char data[4];
-  memset(data, 0, sizeof(data));
-  data[3] = ctrl_cmd;
-  return i2c_write(addr0, ADDR_CTRL, data);
-}
-
-static int i2c_wait(const unsigned char addr0, const unsigned char status)
-{
-  unsigned char buf[9];
-
-  do {
-    if (!i2c_send_read_cmd(addr0, ADDR_STATUS))
-      return 0;
-    if (!i2c_get_resp(buf, sizeof(buf)))
-      return 0;
-    if (buf[1] != READ_OK)
-      return 0;
-  } while ((buf[7] & status) != status);
-
-  if (debug)
-    fprintf(stderr, "[ Done waiting ]\n");
-
-  return 1;
-}
-
-static int i2c_wait_ready(const unsigned char addr0)
-{
-  if (debug)
-    fprintf(stderr, "[ Waiting for ready ]\n");
-  return i2c_wait(addr0, STATUS_READY_BIT);
-}
-
-static int i2c_wait_valid(const unsigned char addr0)
-{
-  if (debug)
-    fprintf(stderr, "[ Waiting for valid ]\n");
-  return i2c_wait(addr0, STATUS_VALID_BIT);
-}
+int debug = 0;
 
 /****************************************************************************
  *                                                                          *
@@ -414,47 +97,44 @@ static int i2c_wait_valid(const unsigned char addr0)
  * Send one block to a core.
  */
 
-static int hash_write_block(const unsigned char addr_prefix,
-                            const unsigned char addr_block,
-                            const unsigned char ctrl_mode,
+static int hash_write_block(const off_t offset,
+                            const uint8_t ctrl_mode,
                             const hash_state_t *state)
 {
-  unsigned char ctrl_cmd;
-  int i;
+  uint8_t ctrl_cmd[4] = { 0 };
+  off_t base = offset & ~(0xff);
 
   assert(state != NULL && state->block_length % 4 == 0);
 
-  for (i = 0; i + 3 < state->block_length; i += 4)
-    if (!i2c_write(addr_prefix, addr_block + i/4, state->block + i))
-      return 0;
+  if (tc_write(offset, state->block, state->block_length) != 0)
+    return CRYPT_ERROR_FAILED;
 
-  ctrl_cmd = state->block_count == 0 ? CTRL_INIT_CMD : CTRL_NEXT_CMD;
+  ctrl_cmd[3] = (state->block_count == 0 ? CTRL_INIT_CMD : CTRL_NEXT_CMD) | ctrl_mode;
 
   if (debug)
     fprintf(stderr, "[ %s ]\n", state->block_count == 0 ? "init" : "next");
 
-  return i2c_ctrl(addr_prefix, ctrl_cmd|ctrl_mode) && i2c_wait_ready(addr_prefix);
+  return
+    tc_write(base + ADDR_CTRL, ctrl_cmd, 4) ||
+    tc_wait_ready(base + ADDR_STATUS);
 }
 
 /*
  * Read hash result from core.
  */
 
-static int hash_read_digest(const unsigned char addr_prefix, const unsigned char addr_digest,
-                            unsigned char *digest, const size_t digest_length)
+static int hash_read_digest(const off_t offset,
+                            unsigned char *digest,
+                            const size_t digest_length)
 {
-  int i;
-
   assert(digest_length % 4 == 0);
 
-  if (!i2c_wait_valid(addr_prefix))
-    return 0;
-
-  for (i = 0; i + 3 < digest_length; i += 4)
-    if (!i2c_read(addr_prefix, addr_digest + i/4, digest + i))
-      return 0;
+  /* Technically, we should poll the status register for the "valid" bit, but
+   * hash_write_block() has already polled for the "ready" bit, and we know
+   * that the sha cores always set valid one clock cycle before ready.
+   */
 
-  return 1;
+  return tc_read(offset, digest, digest_length);
 }
 
 /****************************************************************************
@@ -475,7 +155,7 @@ static int hash_read_digest(const unsigned char addr_prefix, const unsigned char
  * signals this (deliberately?) by returning all zeros.
  */
 
-#define WAIT_FOR_TRNG_VALID	0
+#define WAIT_FOR_TRNG_VALID     0
 
 static int readRandom(void *buffer, const int length)
 {
@@ -492,26 +172,16 @@ static int readRandom(void *buffer, const int length)
   for (i = 0; i < length; i += 4) {
 
 #if WAIT_FOR_TRNG_VALID
-    if (!i2c_wait_valid(TRNG_PREFIX)) {
-      fprintf(stderr, "[ i2c_wait_valid(TRNG_PREFIX) failed ]\n");
-      return 0;
-    }
-    do {
-      if (!i2c_read(TRNG_PREFIX, TRNG_VALID, temp)) {
-        fprintf(stderr, "[ i2c_read(TRNG_VALID) failed ]\n");
-        return 0;
-      }
-    } while (!temp[3]);
-    if (!i2c_wait_valid(TRNG_PREFIX)) {
-      fprintf(stderr, "[ i2c_wait_valid(TRNG_PREFIX) failed ]\n");
-      return 0;
+    if (tc_wait_ready(CSPRNG_ADDR_STATUS) != 0) {
+      fprintf(stderr, "[ tc_wait_valid(CSPRNG_ADDR_STATUS) failed ]\n");
+      return CRYPT_ERROR_FAILED;
     }
 #endif  /* WAIT_FOR_TRNG_VALID */
 
     last = (length - i) < 4;
-    if (!i2c_read(TRNG_PREFIX, TRNG_DATA, (last ? temp : (buf + i)))) {
-      fprintf(stderr, "[ i2c_read(TRNG_DATA) failed ]\n");
-      return 0;
+    if (tc_read(CSPRNG_ADDR_RANDOM, (last ? temp : (buf + i)), 4) != 0) {
+      fprintf(stderr, "[ tc_read(CSPRNG_ADDR_RANDOM) failed ]\n");
+      return CRYPT_ERROR_FAILED;
     }
     if (last) {
       for (; i < length; i++)
@@ -521,10 +191,10 @@ static int readRandom(void *buffer, const int length)
 
   for (i = 0, buf = buffer; i < length; i++, buf++)
     if (*buf != 0)
-      return 1;
+      return CRYPT_OK;
 
   fprintf(stderr, "[ \"Random\" data all zeros, guess TRNG is not installed ]\n");
-  return 0;
+  return CRYPT_ERROR_FAILED;
 }
 
 /****************************************************************************
@@ -562,9 +232,14 @@ static int hashGetInfo(const CAPABILITY_INFO_TYPE type,
  * with a few parameters which we handle via closures below.
  */
 
-static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int length,
-                  const size_t block_length, const unsigned char addr_prefix, const unsigned char addr_block,
-                  const size_t digest_length, const unsigned char addr_digest, const unsigned char ctrl_mode,
+static int doHash(CONTEXT_INFO *contextInfoPtr,
+                  const unsigned char *buffer,
+                  int length,
+                  const size_t block_length,
+                  const off_t addr_block,
+                  const size_t digest_length,
+                  const off_t addr_digest,
+                  const unsigned char ctrl_mode,
                   const size_t length_length)
 {
   hash_state_t *state = NULL;
@@ -605,7 +280,7 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int
       state->block_used = 0;
       length -= n;
       p += n;
-      if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state))
+      if (hash_write_block(addr_block, ctrl_mode, state) != 0)
         return CRYPT_ERROR_FAILED;
       state->block_count++;
     }
@@ -642,7 +317,7 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int
                 (unsigned long) length, (unsigned long) state->block_used, (unsigned long) n, state->msg_length_low);
       if (n > 0)
         memset(state->block + state->block_used, 0, n);
-      if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state))
+      if (hash_write_block(addr_block, ctrl_mode, state) != 0)
         return CRYPT_ERROR_FAILED;
       state->block_count++;
       state->block_used = 0;
@@ -667,14 +342,14 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int
     }
 
     /* Push final block */
-    if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state))
+    if (hash_write_block(addr_block, ctrl_mode, state) != 0)
       return CRYPT_ERROR_FAILED;
     state->block_count++;
 
     /* All data pushed to core, now we just need to read back the result */
 
     assert(digest_length <= sizeof(contextInfoPtr->ctxHash->hash));
-    if (!hash_read_digest(addr_prefix, addr_digest, contextInfoPtr->ctxHash->hash, digest_length))
+    if (hash_read_digest(addr_digest, contextInfoPtr->ctxHash->hash, digest_length) != 0)
       return CRYPT_ERROR_FAILED;
   }
 
@@ -697,7 +372,7 @@ static int sha1SelfTest(void)
 static int sha1Hash(CONTEXT_INFO *contextInfoPtr, unsigned char *buffer, int length)
 {
   return doHash(contextInfoPtr, buffer, length,
-                SHA1_BLOCK_LEN, SHA1_ADDR_PREFIX, SHA1_ADDR_BLOCK,
+                SHA1_BLOCK_LEN, SHA1_ADDR_BLOCK,
                 SHA1_DIGEST_LEN, SHA1_ADDR_DIGEST, 0, SHA1_LENGTH_LEN);
 }
 
@@ -722,18 +397,18 @@ static int sha2Hash(CONTEXT_INFO *contextInfoPtr, unsigned char *buffer, int len
 
   case bitsToBytes(256):
     return doHash(contextInfoPtr, buffer, length,
-                  SHA256_BLOCK_LEN, SHA256_ADDR_PREFIX, SHA256_ADDR_BLOCK,
+                  SHA256_BLOCK_LEN, SHA256_ADDR_BLOCK,
                   SHA256_DIGEST_LEN, SHA256_ADDR_DIGEST, 0, SHA256_LENGTH_LEN);
 
   case bitsToBytes(384):
     return doHash(contextInfoPtr, buffer, length,
-                  SHA512_BLOCK_LEN, SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK,
+                  SHA512_BLOCK_LEN, SHA512_ADDR_BLOCK,
                   SHA384_DIGEST_LEN, SHA512_ADDR_DIGEST, MODE_SHA_384,
                   SHA512_LENGTH_LEN);
 
   case bitsToBytes(512):
     return doHash(contextInfoPtr, buffer, length,
-                  SHA512_BLOCK_LEN, SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK,
+                  SHA512_BLOCK_LEN, SHA512_ADDR_BLOCK,
                   SHA512_DIGEST_LEN, SHA512_ADDR_DIGEST, MODE_SHA_512,
                   SHA512_LENGTH_LEN);
 
@@ -837,10 +512,7 @@ int hwGetRandom(void *buffer, const int length)
 
   REQUIRES(length >= 1 && length < MAX_INTLENGTH);
 
-  if (readRandom(buffer, length))
-    return CRYPT_OK;
-  else
-    return CRYPT_ERROR_RANDOM;
+  return readRandom(buffer, length);
 }
 
 /*
diff --git a/src/novena-eim.c b/src/novena-eim.c
new file mode 100644
index 0000000..85bfac0
--- /dev/null
+++ b/src/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/src/novena-eim.h b/src/novena-eim.h
new file mode 100644
index 0000000..75613bf
--- /dev/null
+++ b/src/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/src/tc_eim.c b/src/tc_eim.c
new file mode 100644
index 0000000..d44b685
--- /dev/null
+++ b/src/tc_eim.c
@@ -0,0 +1,185 @@
+/* 
+ * tc_eim.c
+ * --------
+ * This module contains common code to talk to the FPGA over the EIM bus.
+ * 
+ * Author: Paul Selkirk
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+
+#include "tc_eim.h"
+
+extern int debug;
+static int inited = 0;
+
+/* ---------------- EIM low-level code ---------------- */
+static int init(void)
+{
+    if (inited)
+        return 0;
+
+    if (eim_setup() != 0) {
+        fprintf(stderr, "EIM setup failed\n");
+        return -1;
+    }
+
+    inited = 1;
+    return 0;
+}
+
+/* ---------------- test-case low-level code ---------------- */
+
+static void dump(char *label, const uint8_t *buf, size_t 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, size_t len)
+{
+    if (init() != 0)
+        return -1;
+
+    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, size_t len)
+{
+    uint8_t *rbuf = buf;
+    int rlen = len;
+
+    if (init() != 0)
+        return -1;
+
+    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, size_t 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_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[4] = { 0, 0, 0, CTRL_NEXT_CMD };
+
+    return tc_write(offset, buf, 4);
+}
+
+int tc_wait(off_t offset, uint8_t status, int *count)
+{
+    uint8_t buf[4];
+    int i;
+
+    for (i = 1; ; ++i) {
+        if (count && (*count > 0) && (i >= *count)) {
+            fprintf(stderr, "tc_wait timed out\n");
+            return 1;
+        }
+        if (tc_read(offset, buf, 4) != 0)
+            return -1;
+        if (buf[3] & status) {
+            if (count)
+                *count = i;
+            return 0;
+        }
+    }
+}
+
+int tc_wait_ready(off_t offset)
+{
+    int limit = 256;
+    return tc_wait(offset, STATUS_READY_BIT, &limit);
+}
+
+int tc_wait_valid(off_t offset)
+{
+    int limit = 256;
+    return tc_wait(offset, STATUS_VALID_BIT, &limit);
+}
diff --git a/src/tc_eim.h b/src/tc_eim.h
new file mode 100644
index 0000000..5da18e4
--- /dev/null
+++ b/src/tc_eim.h
@@ -0,0 +1,50 @@
+/* 
+ * tc_eim.h
+ * --------
+ * This module contains common code to talk to the FPGA over the EIM bus.
+ * 
+ * Author: Paul Selkirk
+ * 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.
+ */
+
+#include "novena-eim.h"
+#define BASE_ADDR               EIM_BASE_ADDR
+#define SEGMENT_SIZE            0x10000
+#define ADDR(x)                 (x << 2)
+#include "cryptech_memory_map.h"
+
+/* test case public functions */
+int tc_write(off_t offset, const uint8_t *buf, size_t len);
+int tc_read(off_t offset, uint8_t *buf, size_t len);
+int tc_expected(off_t offset, const uint8_t *expected, size_t len);
+int tc_init(off_t offset);
+int tc_next(off_t offset);
+int tc_wait(off_t offset, uint8_t status, int *count);
+int tc_wait_ready(off_t offset);
+int tc_wait_valid(off_t offset);
diff --git a/src/tc_i2c.c b/src/tc_i2c.c
new file mode 100644
index 0000000..613d1c6
--- /dev/null
+++ b/src/tc_i2c.c
@@ -0,0 +1,331 @@
+/* 
+ * tc_i2c.c
+ * --------
+ * This module contains common code to talk to the FPGA over the I2C bus.
+ * 
+ * Author: Paul Selkirk
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <stdint.h>
+
+#include "tc_i2c.h"
+
+extern int debug;
+
+/* ---------------- I2C low-level code ---------------- */
+
+static int i2cfd = -1;
+
+static void dump(char *label, const uint8_t *buf, size_t len)
+{
+    if (debug) {
+        int i;
+        printf("%s [", label);
+        for (i = 0; i < len; ++i)
+            printf(" %02x", buf[i]);
+        printf(" ]\n");
+    }
+}
+
+static void i2c_close(void)
+{
+    close(i2cfd);
+}
+
+static int i2c_open(void)
+{
+    if (i2cfd >= 0)
+        return 0;
+
+    i2cfd = open(I2C_dev, O_RDWR);
+    if (i2cfd < 0) {
+        fprintf(stderr, "Unable to open %s: ", I2C_dev);
+        perror("");
+        i2cfd = 0;
+        return 1;
+    }
+
+    if (ioctl(i2cfd, I2C_SLAVE, I2C_addr) < 0) {
+        fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", I2C_addr);
+        perror("");
+        return 1;
+    }
+
+    if (atexit(i2c_close) != 0) {
+        fprintf(stderr, "Unable to set I2C atexit handler.");
+        return 1;
+    }
+
+    return 0;
+}
+
+static int i2c_write(const uint8_t *buf, size_t len)
+{
+    if (i2c_open() != 0)
+        return 1;
+
+    dump("write ", buf, len);
+
+    if (write(i2cfd, buf, len) != len) {
+        perror("i2c write failed");
+        return 1;
+    }
+
+    return 0;
+}
+
+static int i2c_read(uint8_t *b)
+{
+    if (i2c_open() != 0)
+        return 1;
+
+    /* read() on the i2c device only returns one byte at a time,
+     * and tc_get_resp() needs to parse the response one byte at a time
+     */
+    if (read(i2cfd, b, 1) != 1) {
+        perror("i2c read failed");
+        return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- test-case low-level code ---------------- */
+
+/* coretest command codes */
+#define SOC       0x55
+#define EOC       0xaa
+#define READ_CMD  0x10
+#define WRITE_CMD 0x11
+#define RESET_CMD 0x01
+
+/* coretest response codes */
+#define SOR       0xaa
+#define EOR       0x55
+#define READ_OK   0x7f
+#define WRITE_OK  0x7e
+#define RESET_OK  0x7d
+#define UNKNOWN   0xfe
+#define ERROR     0xfd
+
+static int tc_send_write_cmd(off_t offset, const uint8_t *data)
+{
+    uint8_t buf[9] = { SOC, WRITE_CMD, (offset >> 8) & 0xff, offset & 0xff,
+                       data[0], data[1], data[2], data[3], EOC };
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+static int tc_send_read_cmd(off_t offset)
+{
+    uint8_t buf[5] = { SOC, READ_CMD, (offset >> 8) & 0xff, offset & 0xff, EOC };
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+static int tc_get_resp(uint8_t *buf, size_t len)
+{
+    int i;
+
+    for (i = 0; i < len; ++i) {
+        if (i2c_read(&buf[i]) != 0)
+            return 1;
+        if ((i == 0) && (buf[i] != SOR)) {
+            /* we've gotten out of sync, and there's probably nothing we can do */
+            fprintf(stderr, "response byte 0: expected 0x%02x (SOR), got 0x%02x\n",
+                    SOR, buf[0]);
+            return 1;
+        }
+        else if (i == 1) {      /* response code */
+            switch (buf[i]) {
+            case READ_OK:
+                len = 9;
+                break;
+            case WRITE_OK:
+                len = 5;
+                break;
+            case RESET_OK:
+                len = 3;
+                break;
+            case ERROR:
+            case UNKNOWN:
+                len = 4;
+                break;
+            default:
+                /* we've gotten out of sync, and there's probably nothing we can do */
+                fprintf(stderr, "unknown response code 0x%02x\n", buf[i]);
+                return 1;
+            }
+        }
+    }
+
+    dump("read  ", buf, len);
+
+    return 0;
+}
+
+static int tc_compare(uint8_t *buf, const uint8_t *expected, size_t len)
+{
+    int i;
+
+    /* start at byte 1 because SOR has already been tested */
+    for (i = 1; 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]);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int tc_get_write_resp(off_t offset)
+{
+    uint8_t buf[5];
+    uint8_t expected[5] = { SOR, WRITE_OK, (offset >> 8) & 0xff, offset & 0xff, EOR };
+
+    return
+        tc_get_resp(buf, sizeof(buf)) ||
+        tc_compare(buf, expected, sizeof(expected));
+}
+
+static int tc_get_read_resp(off_t offset, uint8_t *data)
+{
+    uint8_t buf[9];
+    uint8_t expected[4] = { SOR, READ_OK, (offset >> 8) & 0xff, offset & 0xff };
+
+    if ((tc_get_resp(buf, sizeof(buf)) != 0) ||
+        (tc_compare(buf, expected, 4) != 0) || buf[8] != EOR)
+        return 1;
+
+    data[0] = buf[4];
+    data[1] = buf[5];
+    data[2] = buf[6];
+    data[3] = buf[7];
+
+    return 0;
+}
+
+static int tc_get_read_resp_expected(off_t offset, const uint8_t *data)
+{
+    uint8_t buf[9];
+    uint8_t expected[9] = { SOR, READ_OK, (offset >> 8) & 0xff, offset & 0xff,
+                            data[0], data[1], data[2], data[3], EOR };
+
+    dump("expect", expected, 9);
+
+    return (tc_get_resp(buf, sizeof(buf)) ||
+            tc_compare(buf, expected, sizeof(buf)));
+}
+
+int tc_write(off_t offset, const uint8_t *buf, size_t len)
+{
+    for (; len > 0; offset++, buf += 4, len -= 4) {
+        if (tc_send_write_cmd(offset, buf) ||
+            tc_get_write_resp(offset))
+            return 1;
+    }
+
+    return 0;
+}
+
+int tc_read(off_t offset, uint8_t *buf, size_t len)
+{
+    for (; len > 0; offset++, buf += 4, len -= 4) {
+        if (tc_send_read_cmd(offset) ||
+            tc_get_read_resp(offset, buf))
+            return 1;
+    }
+
+    return 0;
+}
+
+int tc_expected(off_t offset, const uint8_t *buf, size_t len)
+{
+    for (; len > 0; offset++, buf += 4, len -= 4) {
+        if (tc_send_read_cmd(offset) ||
+            tc_get_read_resp_expected(offset, buf))
+            return 1;
+    }
+
+    return 0;
+}
+
+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[4] = { 0, 0, 0, CTRL_NEXT_CMD };
+
+    return tc_write(offset, buf, 4);
+}
+
+int tc_wait(off_t offset, uint8_t status, int *count)
+{
+    uint8_t buf[4];
+    int i;
+
+    for (i = 1; ; ++i) {
+        if (count && (*count > 0) && (i >= *count)) {
+            fprintf(stderr, "tc_wait timed out\n");
+            return 1;
+        }
+        if (tc_read(offset, buf, 4) != 0)
+            return -1;
+        if (buf[3] & status) {
+            if (count)
+                *count = i;
+            return 0;
+        }
+    }
+}
+
+int tc_wait_ready(off_t offset)
+{
+    int limit = 10;
+    return tc_wait(offset, STATUS_READY_BIT, &limit);
+}
+
+int tc_wait_valid(off_t offset)
+{
+    int limit = 10;
+    return tc_wait(offset, STATUS_VALID_BIT, &limit);
+}
diff --git a/src/tc_i2c.h b/src/tc_i2c.h
new file mode 100644
index 0000000..b1afae1
--- /dev/null
+++ b/src/tc_i2c.h
@@ -0,0 +1,55 @@
+/* 
+ * tc_i2c.h
+ * --------
+ * This module contains common code to talk to the FPGA over the I2C bus.
+ * 
+ * Author: Paul Selkirk
+ * 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.
+ */
+
+/* cryptech memory map */
+#define BASE_ADDR               0
+#define SEGMENT_SIZE            0x2000
+#define ADDR(x)                 (x)
+#include "cryptech_memory_map.h"
+
+/* I2C configuration */
+#define I2C_dev                 "/dev/i2c-2"
+#define I2C_addr                0x0f
+#define I2C_SLAVE               0x0703
+
+/* test case public functions */
+int tc_write(off_t offset, const uint8_t *data, size_t len);
+int tc_read(off_t offset, uint8_t *data, size_t len);
+int tc_expected(off_t offset, const uint8_t *data, size_t len);
+int tc_init(off_t offset);
+int tc_next(off_t offset);
+int tc_wait(off_t offset, uint8_t status, int *count);
+int tc_wait_ready(off_t offset);
+int tc_wait_valid(off_t offset);
diff --git a/tests/test_trng.py b/tests/test_trng.py
index 5207eda..1a2177d 100644
--- a/tests/test_trng.py
+++ b/tests/test_trng.py
@@ -44,5 +44,5 @@ if not have_i2c:
     print
     print "[I2C device not found, so testing software only, no hardware cores tested]"
 
-for i in xrange(100):
+for i in xrange(10):
     generate_key(i)



More information about the Commits mailing list