aboutsummaryrefslogblamecommitdiff
path: root/tests/test-bus.c
blob: b4a3e1cdc27e6d643ed9a29ad6db058c131a95e3 (plain) (tree)














































                                                                           
                                                          

   
                                               
 
                                    

                    
                             
                                                                     


                 
                                                                                                


                                                             
                                                                                           




                                                             
                                                                                             















                                                                            
                          




                                                                                   

                                                                              














                                                 
                                                  




                                           
                                                                                               







                                                                 
                                                   




                                           
                                                                                                









                                                                 
                                                                          

                
                                

                 

                                                 


               
/*
 * test-bus.c
 * ----------
 * Test raw read/write performance across the EIM or FMC bus.
 *
 * 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.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

#include <sys/time.h>

#include <hal.h>

#define TEST_NUM_ROUNDS         2000000

/*
 * Sanity test - can we read and write the dummy register?
 */

static int sanity(const hal_core_t *board_core)
{
    uint32_t rnd = 0xdeadbeef, data;
    hal_error_t err;

    if (board_core == NULL) {
        printf("initialization failed (is the bitstream loaded?)\n");
        return 1;
    }

    if ((err = hal_io_write(board_core, 0xFF, (const uint8_t *) &rnd, sizeof(rnd))) != HAL_OK) {
        printf("writing dummy: %s\n", hal_error_string(err));
        return 1;
    }
    if ((err = hal_io_read(board_core, 0xFF, (uint8_t *) &data, sizeof(data))) != HAL_OK) {
        printf("reading dummy: %s\n", hal_error_string(err));
        return 1;
    }

    if (data != rnd) {
        printf("Data bus fail: expected %08x, got %08x, diff %08x\n", rnd, data, data ^ rnd);
        return 1;
    }

    return 0;
}

/*
 * Time a test.
 */

static void _time_check(char *label, const struct timeval t0, const int err)
{
  struct timeval t;
  float rounds;
  gettimeofday(&t, NULL);
  t.tv_sec -= t0.tv_sec;
  t.tv_usec -= t0.tv_usec;
  if (t.tv_usec < 0) {
    t.tv_usec += 1000000;
    t.tv_sec  -= 1;
  }
  rounds = (float)TEST_NUM_ROUNDS/((float)t.tv_sec + ((float)t.tv_usec / 1000000));
  printf("%s%lu.%06lu seconds, %u/sec\n", label,
	 (unsigned long)t.tv_sec, (unsigned long)t.tv_usec, (unsigned)rounds);
}

#define time_check(_label_, _expr_)             \
  do {                                          \
    struct timeval _t;                          \
    gettimeofday(&_t, NULL);                    \
    int _err = (_expr_);                        \
    _time_check(_label_, _t, _err);             \
    err |= _err;                                \
  } while (0)

/*
 * Read and write over and over again.
 */

static int test_read(const hal_core_t *board_core)
{
    uint32_t i, data;
    hal_error_t err;

    for (i = 0; i < TEST_NUM_ROUNDS; ++i) {
	if ((err = hal_io_read(board_core, 0xFF, (uint8_t *) &data, sizeof(data))) != HAL_OK) {
            printf("reading dummy: %s\n", hal_error_string(err));
            return 1;
        }
    }

    return 0;
}

static int test_write(const hal_core_t *board_core)
{
    uint32_t i;
    hal_error_t err;

    for (i = 0; i < TEST_NUM_ROUNDS; ++i) {
	if ((err = hal_io_write(board_core, 0xFF, (const uint8_t *) &i, sizeof(i))) != HAL_OK) {
            printf("writing dummy: %s\n", hal_error_string(err));
            return 1;
        }
    }

    return 0;
}

int main(void)
{
    const hal_core_t *board_core = hal_core_find(NOVENA_BOARD_NAME, NULL);
    int err = 0;

    if (sanity(board_core) != 0)
        return 1;

    time_check("read  ", test_read(board_core));
    time_check("write ", test_write(board_core));

    return err;
}
an> #include "asn1_internal.h" /* * Encode tag and length fields of an ASN.1 object. * * Sets *der_len to the size of of the ASN.1 header (tag and length * fields); caller supplied length of value field, so presumably * already knows it. * * If der is NULL, just return the size of the header that would be * encoded and returns HAL_OK. * * If der isn't NULL, returns HAL_ERROR_RESULT_TOO_LONG unless full * header plus value will fit; this is a bit weird, but is useful when * using this to construct encoders for complte ASN.1 objects. */ hal_error_t hal_asn1_encode_header(const uint8_t tag, const size_t value_len, uint8_t *der, size_t *der_len, const size_t der_max) { size_t header_len = 2; /* Shortest encoding is one octet each for tag and length */ if (value_len >= 128) /* Add octets for longer length encoding as needed */ for (size_t n = value_len; n > 0; n >>= 8) ++header_len; if (der_len != NULL) *der_len = header_len; if (der == NULL) /* If caller just wanted the length, we're done */ return HAL_OK; /* * Make sure there's enough room for header + value, then encode. */ if (value_len + header_len > der_max) return HAL_ERROR_RESULT_TOO_LONG; *der++ = tag; if (value_len < 128) { *der = (uint8_t) value_len; } else { *der = 0x80 | (uint8_t) (header_len -= 2); for (size_t n = value_len; n > 0 && header_len > 0; n >>= 8) der[header_len--] = (uint8_t) (n & 0xFF); } return HAL_OK; } /* * Encode an unsigned ASN.1 INTEGER from a libtfm bignum. If der is * NULL, just return the length of what we would have encoded. */ hal_error_t hal_asn1_encode_integer(const fp_int * const bn, uint8_t *der, size_t *der_len, const size_t der_max) { if (bn == NULL) return HAL_ERROR_BAD_ARGUMENTS; /* * We only handle unsigned INTEGERs, so we need to pad data with a * leading zero if the most significant bit is set, to avoid * flipping the ASN.1 sign bit. Conveniently, this also handles the * difference between libtfm's and ASN.1's encoding of zero. */ if (fp_cmp_d(unconst_fp_int(bn), 0) == FP_LT) return HAL_ERROR_BAD_ARGUMENTS; const int leading_zero = fp_iszero(bn) || (fp_count_bits(unconst_fp_int(bn)) & 7) == 0; const size_t vlen = fp_unsigned_bin_size(unconst_fp_int(bn)) + leading_zero; hal_error_t err; size_t hlen; err = hal_asn1_encode_header(ASN1_INTEGER, vlen, der, &hlen, der_max); if (der_len != NULL) *der_len = hlen + vlen; if (der == NULL || err != HAL_OK) return err; assert(hlen + vlen <= der_max); der += hlen; if (leading_zero) *der++ = 0x00; fp_to_unsigned_bin(unconst_fp_int(bn), der); return HAL_OK; } /* * Encode a public key into an RFC 5280 SubjectPublicKeyInfo. */ hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t alg_oid_len, const uint8_t * const curve_oid, const size_t curve_oid_len, const uint8_t * const pubkey, const size_t pubkey_len, uint8_t *der, size_t *der_len, const size_t der_max) { if (alg_oid == NULL || alg_oid_len == 0 || pubkey_len == 0 || (der != NULL && pubkey == NULL) || (curve_oid == NULL && curve_oid_len != 0)) return HAL_ERROR_BAD_ARGUMENTS; const uint8_t curve_oid_tag = curve_oid == NULL ? ASN1_NULL : ASN1_OBJECT_IDENTIFIER; hal_error_t err; size_t hlen, hlen_spki, hlen_algid, hlen_alg, hlen_curve, hlen_bit; if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, NULL, &hlen_alg, 0)) != HAL_OK || (err = hal_asn1_encode_header(curve_oid_tag, curve_oid_len, NULL, &hlen_curve, 0)) != HAL_OK || (err = hal_asn1_encode_header(ASN1_BIT_STRING, 1 + pubkey_len, NULL, &hlen_bit, 0)) != HAL_OK) return err; const size_t algid_len = hlen_alg + alg_oid_len + hlen_curve + curve_oid_len; if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, NULL, &hlen_algid, 0)) != HAL_OK) return err; const size_t vlen = hlen_algid + hlen_alg + alg_oid_len + hlen_curve + curve_oid_len + hlen_bit + 1 + pubkey_len; if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen_spki, 0)) != HAL_OK) return err; /* * Handle pubkey early, in case it was staged into our output buffer. */ if (der != NULL && hlen_spki + vlen <= der_max) memmove(der + hlen_spki + vlen - pubkey_len, pubkey, pubkey_len); err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max); if (der_len != NULL) *der_len = hlen + vlen; if (der == NULL || err != HAL_OK) return err; uint8_t *d = der + hlen; memset(d, 0, vlen - pubkey_len); if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, d, &hlen, der + der_max - d)) != HAL_OK) return err; d += hlen; if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, d, &hlen, der + der_max - d)) != HAL_OK) return err; d += hlen; memcpy(d, alg_oid, alg_oid_len); d += alg_oid_len; if ((err = hal_asn1_encode_header(curve_oid_tag, curve_oid_len, d, &hlen, der + der_max - d)) != HAL_OK) return err; d += hlen; if (curve_oid != NULL) memcpy(d, curve_oid, curve_oid_len); d += curve_oid_len; if ((err = hal_asn1_encode_header(ASN1_BIT_STRING, 1 + pubkey_len, d, &hlen, der + der_max - d)) != HAL_OK) return err; d += hlen; *d++ = 0x00; d += pubkey_len; /* pubkey handled early, above. */ assert(d == der + hlen_spki + vlen); assert(d <= der + der_max); return HAL_OK; } /* * Parse tag and length of an ASN.1 object. Tag must match value * specified by the caller. On success, sets hlen and vlen to lengths * of header and value, respectively. */ hal_error_t hal_asn1_decode_header(const uint8_t tag, const uint8_t * const der, size_t der_max, size_t *hlen, size_t *vlen) { assert(der != NULL && hlen != NULL && vlen != NULL); if (der_max < 2 || der[0] != tag) return HAL_ERROR_ASN1_PARSE_FAILED; if ((der[1] & 0x80) == 0) { *hlen = 2; *vlen = der[1]; } else { *hlen = 2 + (der[1] & 0x7F); *vlen = 0; if (*hlen > der_max) return HAL_ERROR_ASN1_PARSE_FAILED; for (size_t i = 2; i < *hlen; i++) *vlen = (*vlen << 8) + der[i]; } if (*hlen + *vlen > der_max) return HAL_ERROR_ASN1_PARSE_FAILED; return HAL_OK; } /* * Decode an ASN.1 INTEGER into a libtfm bignum. Since we only * support (or need to support, or expect to see) unsigned integers, * we return failure if the sign bit is set in the ASN.1 INTEGER. */ hal_error_t hal_asn1_decode_integer(fp_int *bn, const uint8_t * const der, size_t *der_len, const size_t der_max) { if (bn == NULL || der == NULL) return HAL_ERROR_BAD_ARGUMENTS; hal_error_t err; size_t hlen, vlen; if ((err = hal_asn1_decode_header(ASN1_INTEGER, der, der_max, &hlen, &vlen)) != HAL_OK) return err; if (der_len != NULL) *der_len = hlen + vlen; if (vlen < 1 || (der[hlen] & 0x80) != 0x00) return HAL_ERROR_ASN1_PARSE_FAILED; fp_init(bn); fp_read_unsigned_bin(bn, (uint8_t *) der + hlen, vlen); return HAL_OK; } /* * Decode a public key from an RFC 5280 SubjectPublicKeyInfo. */ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len, const uint8_t **curve_oid, size_t *curve_oid_len, const uint8_t **pubkey, size_t *pubkey_len, const uint8_t *const der, const size_t der_len) { if (alg_oid == NULL || alg_oid_len == NULL || curve_oid == NULL || curve_oid_len == NULL || pubkey == NULL || pubkey_len == NULL || der == NULL) return HAL_ERROR_BAD_ARGUMENTS; const uint8_t * const der_end = der + der_len; const uint8_t *d = der; size_t hlen, vlen; hal_error_t err; if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK) return err; d += hlen; if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK) return err; d += hlen; const uint8_t * const algid_end = d + vlen; if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK) return err; d += hlen; if (vlen > algid_end - d) return HAL_ERROR_ASN1_PARSE_FAILED; *alg_oid = d; *alg_oid_len = vlen; d += vlen; *curve_oid = NULL; *curve_oid_len = 0; if (d < algid_end) { switch (*d) { case ASN1_OBJECT_IDENTIFIER: if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK) return err; d += hlen; if (vlen > algid_end - d) return HAL_ERROR_ASN1_PARSE_FAILED; *curve_oid = d; *curve_oid_len = vlen; d += vlen; break; case ASN1_NULL: if ((err = hal_asn1_decode_header(ASN1_NULL, d, algid_end - d, &hlen, &vlen)) != HAL_OK) return err; d += hlen; if (vlen == 0) break; default: return HAL_ERROR_ASN1_PARSE_FAILED; } } if (d != algid_end) return HAL_ERROR_ASN1_PARSE_FAILED; if ((err = hal_asn1_decode_header(ASN1_BIT_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK) return err; d += hlen; if (vlen >= algid_end - d || vlen == 0 || *d != 0x00) return HAL_ERROR_ASN1_PARSE_FAILED; *pubkey = ++d; *pubkey_len = --vlen; d += vlen; if (d != der_end) return HAL_ERROR_ASN1_PARSE_FAILED; return HAL_OK; } /* * Local variables: * indent-tabs-mode: nil * End: */