From 2caeaafb9287c1aaef471fc513e97faaaa522b31 Mon Sep 17 00:00:00 2001 From: Christian Mauderer Date: Tue, 16 Mar 2021 14:47:03 +0100 Subject: testsuite/media01: Add pattern test Update #4372 --- libbsd.py | 2 +- testsuite/media01/pattern-test.c | 337 +++++++++++++++++++++++++++++++++++++++ testsuite/media01/pattern-test.h | 44 +++++ testsuite/media01/test_main.c | 5 +- 4 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 testsuite/media01/pattern-test.c create mode 100644 testsuite/media01/pattern-test.h diff --git a/libbsd.py b/libbsd.py index 16e81565..4230c28e 100644 --- a/libbsd.py +++ b/libbsd.py @@ -5237,7 +5237,7 @@ class tests(builder.Module): runTest = False, netTest = True, extraLibs = ['telnetd'])) self.addTest(mm.generator['test']('smp01', ['test_main'], extraLibs = ['rtemstest'])) - self.addTest(mm.generator['test']('media01', ['test_main'], + self.addTest(mm.generator['test']('media01', ['test_main', 'pattern-test'], runTest = False, extraLibs = ['ftpd', 'telnetd'])) self.addTest(mm.generator['test']('mcast01', ['test_main'])) diff --git a/testsuite/media01/pattern-test.c b/testsuite/media01/pattern-test.c new file mode 100644 index 00000000..4b00cb73 --- /dev/null +++ b/testsuite/media01/pattern-test.c @@ -0,0 +1,337 @@ +/** + * @file + * + * @brief Command to fill a file with a pattern. + * + * The written pattern is a simple 32 bit counter which makes it easy to find + * problems where buffers are not written to the correct location or where some + * blocks are missing. + * + * This file can be either compiled as part of RTEMS or as a stand alone Linux + * or (most likely) FreeBSD application. To compile it as stand alone, just use + * "gcc pattern-test.c" + */ + +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2020 embedded brains GmbH. + * + * 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. + * + * 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 OWNER 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. + */ + +#ifdef __rtems__ +#include "pattern-test.h" +#endif /* __rtems__ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + +static const char * const usage = + "Fill a file or a device file with a simple incrementing 32 bit pattern.\n" + "Use with:\n" + " pattern [fill|check] [ []]\n" + "Arguments:\n" + " All numbers can be decimal (e.g. 256) or hex (e.g. 0x100)\n" + " and is in bytes\n" + " start with this counter value\n" + " : Only relevant for check. Can be: \n" + " : print the first errors\n" + " \"short\": Print all errors but short form\n"; + +static int +check_and_process_params( + int argc, + char *argv[], + int open_flags, + int *fd, + size_t *size, + size_t *block_size, + uint8_t **block, + uint8_t **read_block, + int *max_errors, + bool *short_output, + uint32_t *start_value +) +{ + if (argc < 4) { + printf(usage); + return -1; + } + + if (argc > 4) { + *start_value = strtoul(argv[4], NULL, 0); + } else { + *start_value = 0; + } + + if (short_output != NULL && max_errors != NULL) { + *short_output = false; + *max_errors = 1; + if (argc > 5) { + if (strcmp("short", argv[5]) == 0) { + *max_errors = -1; + *short_output = true; + } else { + *max_errors = strtol(argv[5], NULL, 0); + if (*max_errors <= 0) { + warn("Can't use parameter."); + return -1; + } + } + } + } + + *size = strtoul(argv[2], NULL, 0); + if (size == 0) { + warn("Couldn't convert size or size set to 0"); + return -1; + } + + *block_size = strtoul(argv[3], NULL, 0); + if (block_size == 0) { + warn("Couldn't convert block_size or block_size set to 0"); + return -1; + } + + if (block != NULL) { + *block = malloc(*block_size); + if (*block == NULL) { + warn("Couldn't allocate block"); + return -1; + } + } + + if (read_block != NULL) { + *read_block = malloc(*block_size); + if (*read_block == NULL) { + warn("Couldn't allocate read_block"); + if (block != NULL) { + free(*block); + } + return -1; + } + } + + *fd = open(argv[1], open_flags, 0666); + if (*fd < 0) { + warn("Couldn't open file"); + if (block != NULL) { + free(*block); + } + if (read_block != NULL) { + free(*read_block); + } + return -1; + } + + printf("File: %s\nSize: 0x%x\nBlock size: 0x%x\n", + argv[1], *size, *block_size); + + return 0; +} + +/* Write addresses to the block. Keep word boundaries intact. */ +static void +fill_block(uint8_t *block, size_t size, uint32_t start) +{ + uint32_t pattern_size = sizeof(start); + uint32_t start_offset = start % pattern_size; + uint32_t value_h = start & ~(pattern_size - 1); + uint32_t value_n = htonl(value_h); + uint8_t *val = (uint8_t *) &value_n; + + if (start_offset != 0) { + size_t to_write = MIN(pattern_size - start_offset, size); + memcpy(block, val + start_offset, to_write); + block += to_write; + size -= to_write; + value_h += pattern_size; + value_n = htonl(value_h); + } + + while (size >= pattern_size) { + memcpy(block, val, pattern_size); + value_h += pattern_size; + value_n = htonl(value_h); + block += pattern_size; + size -= pattern_size; + } + + if (size > 0) { + memcpy(block, val, size); + } +} + +static int +command_pattern_fill(int argc, char *argv[]) +{ + int fd; + size_t size; + size_t block_size; + uint8_t *block; + uint32_t start_value; + int rv; + + rv = check_and_process_params(argc, argv, O_WRONLY | O_CREAT, + &fd, &size, &block_size, &block, NULL, NULL, NULL, &start_value); + if (rv != 0) { + warnx("Error while processing parameters.\n"); + return rv; + } + + for (size_t current = start_value; + current < start_value + size; + current += block_size) { + size_t write_size = MIN(block_size, size-current); + ssize_t written; + fill_block(block, write_size, current); + written = write(fd, block, write_size); + if (written != (ssize_t)write_size) { + warn("Writing failed on block at 0x%x", current); + break; + } + } + + free(block); + close(fd); + + return 0; +} + +static void +print_block(uint8_t *block, size_t size) +{ + for (size_t i = 0; i < size; ++i) { + if (i > 0 && i % 0x10 == 0) { + printf("\n"); + } + printf("%02x ", block[i]); + } + printf("\n"); +} + +static int +command_pattern_check(int argc, char *argv[]) +{ + int fd; + size_t size; + size_t block_size; + uint8_t *block; + uint8_t *read_block; + int rv; + int errors = 0; + int max_errors; + bool short_output; + bool last_was_error = false; + uint32_t start_value; + + rv = check_and_process_params(argc, argv, O_RDONLY, + &fd, &size, &block_size, &block, &read_block, + &max_errors, &short_output, &start_value); + if (rv != 0) { + warnx("Error while processing parameters.\n"); + return rv; + } + + for (size_t current = start_value; + current < size + start_value; + current += block_size) { + size_t read_size = MIN(block_size, size-current); + ssize_t received; + fill_block(block, read_size, current); + received = read(fd, read_block, read_size); + if (received != (ssize_t)read_size) { + warn("Reading failed on block at 0x%x", current); + break; + } + rv = memcmp(block, read_block, read_size); + if (short_output) { + bool is_error = (rv != 0); + if (last_was_error != is_error) { + warnx("%s: 0x%x", + is_error ? "ERR" : "OK ", + current); + } + last_was_error = is_error; + } else if (rv != 0) { + warnx("Pattern wrong in block at 0x%x", current); + warnx("Expected:"); + print_block(block, read_size); + warnx("Got:"); + print_block(read_block, read_size); + ++errors; + if (errors >= max_errors) { + warnx("Too many errors. Refusing to continue."); + break; + } + } + } + + free(read_block); + free(block); + close(fd); + + return 0; +} + +static int +command_pattern(int argc, char *argv[]) +{ + if (argc < 2) { + printf(usage); + return -1; + } else if (strcmp(argv[1], "fill") == 0) { + return command_pattern_fill(argc-1, &argv[1]); + } else if (strcmp(argv[1], "check") == 0) { + return command_pattern_check(argc-1, &argv[1]); + } else { + printf(usage); + return -1; + } +} + +#ifdef __rtems__ +rtems_shell_cmd_t shell_PATTERN_Command = { + .name = "pattern", + .usage = usage, + .topic = "files", + .command = command_pattern, +}; +#else /* __rtems__ */ + +int +main(int argc, char *argv[]) +{ + return command_pattern(argc, argv); +} +#endif /* __rtems__ */ diff --git a/testsuite/media01/pattern-test.h b/testsuite/media01/pattern-test.h new file mode 100644 index 00000000..5d89e16c --- /dev/null +++ b/testsuite/media01/pattern-test.h @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2020 embedded brains GmbH. + * + * 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. + * + * 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 OWNER 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. + */ + +#ifndef TESTSUITE_PATTERN_H +#define TESTSUITE_PATTERN_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern rtems_shell_cmd_t shell_PATTERN_Command; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* TESTSUITE_PATTERN_H */ diff --git a/testsuite/media01/test_main.c b/testsuite/media01/test_main.c index 9c05fc07..2a1c9aae 100644 --- a/testsuite/media01/test_main.c +++ b/testsuite/media01/test_main.c @@ -53,6 +53,8 @@ #include #include +#include "pattern-test.h" + #define TEST_NAME "LIBBSD MEDIA 1" #define TEST_STATE_USER_INPUT 1 @@ -241,7 +243,8 @@ early_initialization(void) &rtems_shell_SYSCTL_Command, \ &rtems_shell_IFCONFIG_Command, \ &rtems_shell_IFMCSTAT_Command, \ - &rtems_shell_VMSTAT_Command + &rtems_shell_VMSTAT_Command, \ + &shell_PATTERN_Command #define CONFIGURE_SHELL_COMMAND_CPUINFO #define CONFIGURE_SHELL_COMMAND_CPUUSE -- cgit v1.2.3