/* -*- mode:C; c-file-style: "bsd" -*- */ /* * * Copyright (c) 2014 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: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. 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. * * Author: Fredrik Thulin */ #include #include #include #include #include #include #include #include #include /* XXX should runtime check if this is a little-endian system already */ #define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24)) #define INPUT_BLOCK_SIZE 1024 #define SYNC_BYTE 0xf0 #define NUM_SYNC_BYTES 16 enum { mode_random = 0, mode_random_VN, mode_deltas, }; const char *usage = "This program parses the output of MODE_DELTAS in the STM32 code.\n" "\n" "Usage: delta16 [options] [infile] [outfile]\n" "\n" "Options:\n" " -V von Neumann de-biased random bytes output\n" " -D counter delta output\n" " -v verbose\n" " -d debug\n" " -f force overwriting of existing output file\n" "" "\n" ; const char *optstring = "VDvfd"; int parse_args(int argc, char **argv, int *mode, char **infile, char **outfile, int *verbose, int *force, int *debug, int *exit_code) { int c, V = 0, D = 0; while((c = getopt(argc, argv, optstring)) != -1) { switch (c) { case 'V': V = 1; break; case 'D': D = 1; break; case 'v': *verbose = 1; break; case 'f': *force = 1; break; case 'd': *debug = 1; break; default: fputs(usage, stderr); *exit_code = 0; return 0; } } *mode = mode_random; if (V && D) { fprintf(stderr, "Options -V and -D can't be combined\n"); return 0; } if (V) { *mode = mode_random_VN; } if (D) { *mode = mode_deltas; } *infile = "-"; *outfile = "-"; if (optind < argc) { *infile = argv[optind++]; } if (optind < argc) { *outfile = argv[optind++]; } return 1; } int find_input_sync_position(FILE *in, const int verbose) { int pos = 0; int match = 0; uint8_t ch; while (pos++ < 4096) { if (! fread(&ch, 1, 1, in)) { return 0; } if (ch == SYNC_BYTE) { match++; if (match == NUM_SYNC_BYTES) { return pos; } } else { match = 0; } } return -1; } int fill_input_buffer(FILE *in, uint8_t *buf, size_t bufsize, int verbose, unsigned long *skipped_bytes) { int i; unsigned long pos = 0, old_pos = 0; old_pos = ftell(in); if ((i = fread(buf, 1, bufsize, in)) != INPUT_BLOCK_SIZE) { if (verbose) { fprintf(stderr, "Short read, %d bytes, at position %ld / %lx\n", i, old_pos, old_pos); } return 2; } /* Expect next sync marker to immediately follow this one */ if ((i = find_input_sync_position(in, verbose)) > NUM_SYNC_BYTES) { /* fprintf(stderr, "SYNC: buf[0] from pos %ld / %lx was 0x%2x - sync found at + %d (now at %ld / %lx)\n", old_pos, old_pos, buf[0], i, ftell(in), ftell(in)); */ if (i < 0) { fprintf(stderr, "Sync completely lost from position %ld / %lx\n", old_pos, old_pos); return 0; } if (fseek(in, 0 - INPUT_BLOCK_SIZE, SEEK_CUR) < 0) { fprintf(stderr, "Failed seeking backwards when looking for sync from position %ld / %lx\n", old_pos, old_pos); return 0; } i = find_input_sync_position(in, verbose); pos = ftell(in); if (i < INPUT_BLOCK_SIZE - 1) { fprintf(stderr, "Short block (%d bytes, < %d) at position %ld / %lx. Resynced at %ld / 0x%lx.\n", i, INPUT_BLOCK_SIZE, old_pos, old_pos, pos, pos); } else { if (verbose) { fprintf(stderr, "Sync lost, skipping %ld bytes from position %ld / 0x%lx. Resynced at %ld / 0x%lx.\n", pos - old_pos, old_pos, old_pos, pos, pos); } *skipped_bytes += pos - old_pos; return -1; } } return 1; } inline void output_deltas(FILE *out, uint32_t raw, unsigned long *write_count, int debug) { uint32_t first, second; static uint32_t last = 0, num = 0; first = (raw & 0xffff0000) >> 16; second = (raw & 0x0000ffff); if (last > first) { /* Next batch of timer values start here */ last = 0; num = 0; } /* Need to skip the first output of each batch - it's delta value is unknown */ if (num) { fprintf(out, "%02d %04x %02x\n", num++, first, first - last); *write_count += 1; } else { num++; } fprintf(out, "%02d %04x %02x\n", num++, second, second - first); *write_count += 1; last = second; } inline void output_random(FILE *out, uint32_t raw, unsigned long *write_count, int debug) { uint32_t first, second; static uint32_t num = 0, bits = 0, old_bits; first = (raw & 0xffff0000) >> 16; second = (raw & 0x0000ffff); old_bits = bits; bits <<= 1; bits += (first & 1); bits <<= 1; bits += (second & 1); num += 2; if (debug) { fprintf(stderr, "raw 0x%08x -> first 0x%04x second 0x%04x bits 0x%x |= %d |= %d -> 0x%x (%d bits)\n", raw, first, second, old_bits, (first & 1), (second & 1), bits, num); } if (num == 32) { if (debug) { fprintf(stderr, "write %02x %02x %02x %02x\n", (bits & 0xff000000) >> 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8, bits & 0xff ); } fprintf(out, "%c%c%c%c", (bits & 0xff000000) >> 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8, bits & 0xff ); *write_count += 4; bits = 0; num = 0; } } inline void output_random_VN(FILE *out, uint32_t raw, unsigned long *write_count, int debug) { uint32_t first, second; static uint32_t num = 0, bits = 0, old_bits; first = (raw & 0xffff0000) >> 16; second = (raw & 0x0000ffff); /* Discard both values unless their LSB is actually different. This is the Von Neumann extractor. */ if ((first & 1) != (second & 1)) { old_bits = bits; bits <<= 1; bits += (first & 1); num++; if (debug) { fprintf(stderr, "raw 0x%08x -> first 0x%04x second 0x%04x bits 0x%x |= %d (skip second %d)-> 0x%x (%d bits)\n", raw, first, second, old_bits, (first & 1), (second & 1), bits, num); } } else if (debug) { fprintf(stderr, "raw 0x%08x -> first 0x%04x second 0x%04x\n", raw, first, second); } if (num == 32) { fprintf(out, "%c%c%c%c", (bits & 0xff000000) >> 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8, bits & 0xff ); *write_count += 4; num = 0; bits = 0; } } int process_data(FILE *in, FILE *out, const int verbose, const int debug, const int mode, unsigned long *skipped_bytes ) { unsigned long blocks = 0, skipped_blocks = 0, write_count = 0; uint32_t i, raw = 0; uint32_t *buf32, *buf32_end; uint8_t buf[INPUT_BLOCK_SIZE]; if (skipped_bytes) { skipped_blocks = 1; } while (1) { if ((i = fill_input_buffer(in, buf, sizeof(buf), verbose, skipped_bytes)) != 1) { if (i == -1) { skipped_blocks += 1; continue; } if (i == 2) { /* short read - EOF */ unsigned long counters = (blocks * INPUT_BLOCK_SIZE / 2); fprintf(stderr, "------ delta16 ------\n"); fprintf(stderr, "Skipped %ld blocks (%ld bytes total) because of loss of sync.\n", skipped_blocks, *skipped_bytes); fprintf(stderr, "Processed %ld * %d = %ld bytes (%ld MB). %ld counter values.\n", blocks, INPUT_BLOCK_SIZE, blocks * INPUT_BLOCK_SIZE, blocks * INPUT_BLOCK_SIZE / 1024 / 1024, counters ); if (mode != mode_deltas) { fprintf(stderr, "Output count is %ld bytes (%ld MB), %.3f counters per output value.\n", write_count, write_count / 1024 / 1024, counters / (double) write_count); } fprintf(stderr, "------ delta16 ------\n\n"); return 1; } } buf32 = (uint32_t *) buf; buf32_end = &buf32[INPUT_BLOCK_SIZE / sizeof(buf32[0])]; while (buf32 < buf32_end) { /* fprintf(stderr, "Read %d @%p\n", i, &buf32); */ raw = *buf32++; switch (mode) { case mode_deltas: output_deltas(out, raw, &write_count, debug); break;; case mode_random: output_random(out, raw, &write_count, debug); break;; case mode_random_VN: output_random_VN(out, raw, &write_count, debug); break;; default: fprintf(stderr, "Mode %d output not implemented, aborting\n", mode); return 0; } } blocks++; if (verbose && ! (blocks % 100000) && blocks) { fprintf(stderr, "Processed %ld blocks (file position %ld / 0x%lx / %ld MB)\n", blocks, ftell(in), ftell(in), ftell(in) / 1024 / 1024); } }; /* NOT REACHED */ return 0; } int main(int argc, char **argv) { int mode, debug = 0, verbose = 0, force = 0, exit_code = 1; unsigned long skipped_bytes = 0; char *infile, *outfile; FILE *in, *out; if (! parse_args(argc, argv, &mode, &infile, &outfile, &verbose, &force, &debug, &exit_code )) goto err; if (! strcmp(infile, "-")) { in = stdin; } else { if (verbose) { fprintf(stderr, "Opening input file '%s' for reading\n", infile); } if (! (in = fopen(infile, "rb"))) { fprintf(stderr, "Failed opening input file '%s' for reading: %s\n", infile, strerror(errno)); goto err; } } if ((skipped_bytes = find_input_sync_position(in, verbose)) < 0) { fprintf(stderr, "Could not find sync sequence in input\n"); goto err; } if (verbose) { fprintf(stderr, "Initial sync found at position %ld / 0x%lx\n", skipped_bytes, skipped_bytes); } if (! strcmp(outfile, "-")) { out = stdout; } else { if (! force) { /* Check that file does not already exist */ if (access(outfile, F_OK) == F_OK) { fprintf(stderr, "Refusing to overwrite existing output file without -f (force)\n"); goto err; } } if (verbose) { fprintf(stderr, "Opening output file '%s' for writing\n", outfile); } if (! (out = fopen(outfile, "wb"))) { fprintf(stderr, "Failed opening output file '%s' for writing: %s\n", outfile, strerror(errno)); goto err; } } if (! process_data(in, out, verbose, debug, mode, &skipped_bytes)) { fprintf(stderr, "Failed processing data\n"); goto err; } exit_code = 0; err: exit(exit_code); }