cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adi-test.c (16598B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * selftest for sparc64's privileged ADI driver
      4 *
      5 * Author: Tom Hromatka <tom.hromatka@oracle.com>
      6 */
      7#include <linux/kernel.h>
      8#include <errno.h>
      9#include <fcntl.h>
     10#include <stdarg.h>
     11#include <stdio.h>
     12#include <stdlib.h>
     13#include <string.h>
     14#include <sys/syscall.h>
     15#include <sys/types.h>
     16#include <sys/stat.h>
     17#include <unistd.h>
     18
     19#include "../../kselftest.h"
     20
     21#define DEBUG_LEVEL_1_BIT	(0x0001)
     22#define DEBUG_LEVEL_2_BIT	(0x0002)
     23#define DEBUG_LEVEL_3_BIT	(0x0004)
     24#define DEBUG_LEVEL_4_BIT	(0x0008)
     25#define DEBUG_TIMING_BIT	(0x1000)
     26
     27/* bit mask of enabled bits to print */
     28#define DEBUG 0x0001
     29
     30#define DEBUG_PRINT_L1(...)	debug_print(DEBUG_LEVEL_1_BIT, __VA_ARGS__)
     31#define DEBUG_PRINT_L2(...)	debug_print(DEBUG_LEVEL_2_BIT, __VA_ARGS__)
     32#define DEBUG_PRINT_L3(...)	debug_print(DEBUG_LEVEL_3_BIT, __VA_ARGS__)
     33#define DEBUG_PRINT_L4(...)	debug_print(DEBUG_LEVEL_4_BIT, __VA_ARGS__)
     34#define DEBUG_PRINT_T(...)	debug_print(DEBUG_TIMING_BIT, __VA_ARGS__)
     35
     36static void debug_print(int level, const char *s, ...)
     37{
     38	va_list args;
     39
     40	va_start(args, s);
     41
     42	if (DEBUG & level)
     43		vfprintf(stdout, s, args);
     44	va_end(args);
     45}
     46
     47#ifndef min
     48#define min(x, y) ((x) < (y) ? x : y)
     49#endif
     50
     51#define RETURN_FROM_TEST(_ret) \
     52	do { \
     53		DEBUG_PRINT_L1( \
     54			"\tTest %s returned %d\n", __func__, _ret); \
     55		return _ret; \
     56	} while (0)
     57
     58#define ADI_BLKSZ	64
     59#define ADI_MAX_VERSION	15
     60
     61#define TEST_STEP_FAILURE(_ret) \
     62	do { \
     63		fprintf(stderr, "\tTest step failure: %d at %s:%d\n", \
     64			_ret, __func__, __LINE__); \
     65		goto out; \
     66	} while (0)
     67
     68#define RDTICK(_x) \
     69	asm volatile(" rd %%tick, %0\n" : "=r" (_x))
     70
     71static int random_version(void)
     72{
     73	long tick;
     74
     75	RDTICK(tick);
     76
     77	return tick % (ADI_MAX_VERSION + 1);
     78}
     79
     80#define MAX_RANGES_SUPPORTED	5
     81static const char system_ram_str[] = "System RAM\n";
     82static int range_count;
     83static unsigned long long int start_addr[MAX_RANGES_SUPPORTED];
     84static unsigned long long int   end_addr[MAX_RANGES_SUPPORTED];
     85
     86struct stats {
     87	char		name[16];
     88	unsigned long	total;
     89	unsigned long	count;
     90	unsigned long	bytes;
     91};
     92
     93static struct stats read_stats = {
     94	.name = "read", .total = 0, .count = 0, .bytes = 0};
     95static struct stats pread_stats = {
     96	.name = "pread", .total = 0, .count = 0, .bytes = 0};
     97static struct stats write_stats = {
     98	.name = "write", .total = 0, .count = 0, .bytes = 0};
     99static struct stats pwrite_stats = {
    100	.name = "pwrite", .total = 0, .count = 0, .bytes = 0};
    101static struct stats seek_stats = {
    102	.name = "seek", .total = 0, .count = 0, .bytes = 0};
    103
    104static void update_stats(struct stats * const ustats,
    105			 unsigned long measurement, unsigned long bytes)
    106{
    107	ustats->total += measurement;
    108	ustats->bytes += bytes;
    109	ustats->count++;
    110}
    111
    112static void print_ustats(const struct stats * const ustats)
    113{
    114	DEBUG_PRINT_L1("%s\t%7d\t%7.0f\t%7.0f\n",
    115		       ustats->name, ustats->count,
    116		       (float)ustats->total / (float)ustats->count,
    117		       (float)ustats->bytes / (float)ustats->count);
    118}
    119
    120static void print_stats(void)
    121{
    122	DEBUG_PRINT_L1("\nSyscall\tCall\tAvgTime\tAvgSize\n"
    123		       "\tCount\t(ticks)\t(bytes)\n"
    124		       "-------------------------------\n");
    125
    126	print_ustats(&read_stats);
    127	print_ustats(&pread_stats);
    128	print_ustats(&write_stats);
    129	print_ustats(&pwrite_stats);
    130	print_ustats(&seek_stats);
    131}
    132
    133static int build_memory_map(void)
    134{
    135	char line[256];
    136	FILE *fp;
    137	int i;
    138
    139	range_count = 0;
    140
    141	fp = fopen("/proc/iomem", "r");
    142	if (!fp) {
    143		fprintf(stderr, "/proc/iomem: error %d: %s\n",
    144			errno, strerror(errno));
    145		return -errno;
    146	}
    147
    148	while (fgets(line, sizeof(line), fp) != 0) {
    149		if (strstr(line, system_ram_str)) {
    150			char *dash, *end_ptr;
    151
    152			/* Given a line like this:
    153			 * d0400000-10ffaffff : System RAM
    154			 * replace the "-" with a space
    155			 */
    156			dash = strstr(line, "-");
    157			dash[0] = 0x20;
    158
    159			start_addr[range_count] = strtoull(line, &end_ptr, 16);
    160			end_addr[range_count] = strtoull(end_ptr, NULL, 16);
    161			range_count++;
    162		}
    163	}
    164
    165	fclose(fp);
    166
    167	DEBUG_PRINT_L1("RAM Ranges\n");
    168	for (i = 0; i < range_count; i++)
    169		DEBUG_PRINT_L1("\trange %d: 0x%llx\t- 0x%llx\n",
    170			       i, start_addr[i], end_addr[i]);
    171
    172	if (range_count == 0) {
    173		fprintf(stderr, "No valid address ranges found.  Error.\n");
    174		return -1;
    175	}
    176
    177	return 0;
    178}
    179
    180static int read_adi(int fd, unsigned char *buf, int buf_sz)
    181{
    182	int ret, bytes_read = 0;
    183	long start, end, elapsed_time = 0;
    184
    185	do {
    186		RDTICK(start);
    187		ret = read(fd, buf + bytes_read, buf_sz - bytes_read);
    188		RDTICK(end);
    189		if (ret < 0)
    190			return -errno;
    191
    192		elapsed_time += end - start;
    193		update_stats(&read_stats, elapsed_time, buf_sz);
    194		bytes_read += ret;
    195
    196	} while (bytes_read < buf_sz);
    197
    198	DEBUG_PRINT_T("\tread elapsed timed = %ld\n", elapsed_time);
    199	DEBUG_PRINT_L3("\tRead  %d bytes\n", bytes_read);
    200
    201	return bytes_read;
    202}
    203
    204static int pread_adi(int fd, unsigned char *buf,
    205		     int buf_sz, unsigned long offset)
    206{
    207	int ret, i, bytes_read = 0;
    208	unsigned long cur_offset;
    209	long start, end, elapsed_time = 0;
    210
    211	cur_offset = offset;
    212	do {
    213		RDTICK(start);
    214		ret = pread(fd, buf + bytes_read, buf_sz - bytes_read,
    215			    cur_offset);
    216		RDTICK(end);
    217		if (ret < 0)
    218			return -errno;
    219
    220		elapsed_time += end - start;
    221		update_stats(&pread_stats, elapsed_time, buf_sz);
    222		bytes_read += ret;
    223		cur_offset += ret;
    224
    225	} while (bytes_read < buf_sz);
    226
    227	DEBUG_PRINT_T("\tpread elapsed timed = %ld\n", elapsed_time);
    228	DEBUG_PRINT_L3("\tRead  %d bytes starting at offset 0x%lx\n",
    229		       bytes_read, offset);
    230	for (i = 0; i < bytes_read; i++)
    231		DEBUG_PRINT_L4("\t\t0x%lx\t%d\n", offset + i, buf[i]);
    232
    233	return bytes_read;
    234}
    235
    236static int write_adi(int fd, const unsigned char * const buf, int buf_sz)
    237{
    238	int ret, bytes_written = 0;
    239	long start, end, elapsed_time = 0;
    240
    241	do {
    242		RDTICK(start);
    243		ret = write(fd, buf + bytes_written, buf_sz - bytes_written);
    244		RDTICK(end);
    245		if (ret < 0)
    246			return -errno;
    247
    248		elapsed_time += (end - start);
    249		update_stats(&write_stats, elapsed_time, buf_sz);
    250		bytes_written += ret;
    251	} while (bytes_written < buf_sz);
    252
    253	DEBUG_PRINT_T("\twrite elapsed timed = %ld\n", elapsed_time);
    254	DEBUG_PRINT_L3("\tWrote %d of %d bytes\n", bytes_written, buf_sz);
    255
    256	return bytes_written;
    257}
    258
    259static int pwrite_adi(int fd, const unsigned char * const buf,
    260		      int buf_sz, unsigned long offset)
    261{
    262	int ret, bytes_written = 0;
    263	unsigned long cur_offset;
    264	long start, end, elapsed_time = 0;
    265
    266	cur_offset = offset;
    267
    268	do {
    269		RDTICK(start);
    270		ret = pwrite(fd, buf + bytes_written,
    271			     buf_sz - bytes_written, cur_offset);
    272		RDTICK(end);
    273		if (ret < 0) {
    274			fprintf(stderr, "pwrite(): error %d: %s\n",
    275				errno, strerror(errno));
    276			return -errno;
    277		}
    278
    279		elapsed_time += (end - start);
    280		update_stats(&pwrite_stats, elapsed_time, buf_sz);
    281		bytes_written += ret;
    282		cur_offset += ret;
    283
    284	} while (bytes_written < buf_sz);
    285
    286	DEBUG_PRINT_T("\tpwrite elapsed timed = %ld\n", elapsed_time);
    287	DEBUG_PRINT_L3("\tWrote %d of %d bytes starting at address 0x%lx\n",
    288		       bytes_written, buf_sz, offset);
    289
    290	return bytes_written;
    291}
    292
    293static off_t seek_adi(int fd, off_t offset, int whence)
    294{
    295	long start, end;
    296	off_t ret;
    297
    298	RDTICK(start);
    299	ret = lseek(fd, offset, whence);
    300	RDTICK(end);
    301	DEBUG_PRINT_L2("\tlseek ret = 0x%llx\n", ret);
    302	if (ret < 0)
    303		goto out;
    304
    305	DEBUG_PRINT_T("\tlseek elapsed timed = %ld\n", end - start);
    306	update_stats(&seek_stats, end - start, 0);
    307
    308out:
    309	(void)lseek(fd, 0, SEEK_END);
    310	return ret;
    311}
    312
    313static int test0_prpw_aligned_1byte(int fd)
    314{
    315	/* somewhat arbitrarily chosen address */
    316	unsigned long paddr =
    317		(end_addr[range_count - 1] - 0x1000) & ~(ADI_BLKSZ - 1);
    318	unsigned char version[1], expected_version;
    319	loff_t offset;
    320	int ret;
    321
    322	version[0] = random_version();
    323	expected_version = version[0];
    324
    325	offset = paddr / ADI_BLKSZ;
    326
    327	ret = pwrite_adi(fd, version, sizeof(version), offset);
    328	if (ret != sizeof(version))
    329		TEST_STEP_FAILURE(ret);
    330
    331	ret = pread_adi(fd, version, sizeof(version), offset);
    332	if (ret != sizeof(version))
    333		TEST_STEP_FAILURE(ret);
    334
    335	if (expected_version != version[0]) {
    336		DEBUG_PRINT_L2("\tExpected version %d but read version %d\n",
    337			       expected_version, version[0]);
    338		TEST_STEP_FAILURE(-expected_version);
    339	}
    340
    341	ret = 0;
    342out:
    343	RETURN_FROM_TEST(ret);
    344}
    345
    346#define TEST1_VERSION_SZ	4096
    347static int test1_prpw_aligned_4096bytes(int fd)
    348{
    349	/* somewhat arbitrarily chosen address */
    350	unsigned long paddr =
    351		(end_addr[range_count - 1] - 0x6000) & ~(ADI_BLKSZ - 1);
    352	unsigned char version[TEST1_VERSION_SZ],
    353		expected_version[TEST1_VERSION_SZ];
    354	loff_t offset;
    355	int ret, i;
    356
    357	for (i = 0; i < TEST1_VERSION_SZ; i++) {
    358		version[i] = random_version();
    359		expected_version[i] = version[i];
    360	}
    361
    362	offset = paddr / ADI_BLKSZ;
    363
    364	ret = pwrite_adi(fd, version, sizeof(version), offset);
    365	if (ret != sizeof(version))
    366		TEST_STEP_FAILURE(ret);
    367
    368	ret = pread_adi(fd, version, sizeof(version), offset);
    369	if (ret != sizeof(version))
    370		TEST_STEP_FAILURE(ret);
    371
    372	for (i = 0; i < TEST1_VERSION_SZ; i++) {
    373		if (expected_version[i] != version[i]) {
    374			DEBUG_PRINT_L2(
    375				"\tExpected version %d but read version %d\n",
    376				expected_version, version[0]);
    377			TEST_STEP_FAILURE(-expected_version[i]);
    378		}
    379	}
    380
    381	ret = 0;
    382out:
    383	RETURN_FROM_TEST(ret);
    384}
    385
    386#define TEST2_VERSION_SZ	10327
    387static int test2_prpw_aligned_10327bytes(int fd)
    388{
    389	/* somewhat arbitrarily chosen address */
    390	unsigned long paddr =
    391		(start_addr[0] + 0x6000) & ~(ADI_BLKSZ - 1);
    392	unsigned char version[TEST2_VERSION_SZ],
    393		expected_version[TEST2_VERSION_SZ];
    394	loff_t offset;
    395	int ret, i;
    396
    397	for (i = 0; i < TEST2_VERSION_SZ; i++) {
    398		version[i] = random_version();
    399		expected_version[i] = version[i];
    400	}
    401
    402	offset = paddr / ADI_BLKSZ;
    403
    404	ret = pwrite_adi(fd, version, sizeof(version), offset);
    405	if (ret != sizeof(version))
    406		TEST_STEP_FAILURE(ret);
    407
    408	ret = pread_adi(fd, version, sizeof(version), offset);
    409	if (ret != sizeof(version))
    410		TEST_STEP_FAILURE(ret);
    411
    412	for (i = 0; i < TEST2_VERSION_SZ; i++) {
    413		if (expected_version[i] != version[i]) {
    414			DEBUG_PRINT_L2(
    415				"\tExpected version %d but read version %d\n",
    416				expected_version, version[0]);
    417			TEST_STEP_FAILURE(-expected_version[i]);
    418		}
    419	}
    420
    421	ret = 0;
    422out:
    423	RETURN_FROM_TEST(ret);
    424}
    425
    426#define TEST3_VERSION_SZ	12541
    427static int test3_prpw_unaligned_12541bytes(int fd)
    428{
    429	/* somewhat arbitrarily chosen address */
    430	unsigned long paddr =
    431		((start_addr[0] + 0xC000) & ~(ADI_BLKSZ - 1)) + 17;
    432	unsigned char version[TEST3_VERSION_SZ],
    433		expected_version[TEST3_VERSION_SZ];
    434	loff_t offset;
    435	int ret, i;
    436
    437	for (i = 0; i < TEST3_VERSION_SZ; i++) {
    438		version[i] = random_version();
    439		expected_version[i] = version[i];
    440	}
    441
    442	offset = paddr / ADI_BLKSZ;
    443
    444	ret = pwrite_adi(fd, version, sizeof(version), offset);
    445	if (ret != sizeof(version))
    446		TEST_STEP_FAILURE(ret);
    447
    448	ret = pread_adi(fd, version, sizeof(version), offset);
    449	if (ret != sizeof(version))
    450		TEST_STEP_FAILURE(ret);
    451
    452	for (i = 0; i < TEST3_VERSION_SZ; i++) {
    453		if (expected_version[i] != version[i]) {
    454			DEBUG_PRINT_L2(
    455				"\tExpected version %d but read version %d\n",
    456				expected_version, version[0]);
    457			TEST_STEP_FAILURE(-expected_version[i]);
    458		}
    459	}
    460
    461	ret = 0;
    462out:
    463	RETURN_FROM_TEST(ret);
    464}
    465
    466static int test4_lseek(int fd)
    467{
    468#define	OFFSET_ADD	(0x100)
    469#define OFFSET_SUBTRACT	(0xFFFFFFF000000000)
    470
    471	off_t offset_out, offset_in;
    472	int ret;
    473
    474
    475	offset_in = 0x123456789abcdef0;
    476	offset_out = seek_adi(fd, offset_in, SEEK_SET);
    477	if (offset_out != offset_in) {
    478		ret = -1;
    479		TEST_STEP_FAILURE(ret);
    480	}
    481
    482	/* seek to the current offset.  this should return EINVAL */
    483	offset_out = seek_adi(fd, offset_in, SEEK_SET);
    484	if (offset_out < 0 && errno == EINVAL)
    485		DEBUG_PRINT_L2(
    486			"\tSEEK_SET failed as designed. Not an error\n");
    487	else {
    488		ret = -2;
    489		TEST_STEP_FAILURE(ret);
    490	}
    491
    492	offset_out = seek_adi(fd, 0, SEEK_CUR);
    493	if (offset_out != offset_in) {
    494		ret = -3;
    495		TEST_STEP_FAILURE(ret);
    496	}
    497
    498	offset_out = seek_adi(fd, OFFSET_ADD, SEEK_CUR);
    499	if (offset_out != (offset_in + OFFSET_ADD)) {
    500		ret = -4;
    501		TEST_STEP_FAILURE(ret);
    502	}
    503
    504	offset_out = seek_adi(fd, OFFSET_SUBTRACT, SEEK_CUR);
    505	if (offset_out != (offset_in + OFFSET_ADD + OFFSET_SUBTRACT)) {
    506		ret = -5;
    507		TEST_STEP_FAILURE(ret);
    508	}
    509
    510	ret = 0;
    511out:
    512	RETURN_FROM_TEST(ret);
    513}
    514
    515static int test5_rw_aligned_1byte(int fd)
    516{
    517	/* somewhat arbitrarily chosen address */
    518	unsigned long paddr =
    519		(end_addr[range_count - 1] - 0xF000) & ~(ADI_BLKSZ - 1);
    520	unsigned char version, expected_version;
    521	loff_t offset;
    522	off_t oret;
    523	int ret;
    524
    525	offset = paddr / ADI_BLKSZ;
    526	version = expected_version = random_version();
    527
    528	oret = seek_adi(fd, offset, SEEK_SET);
    529	if (oret != offset) {
    530		ret = -1;
    531		TEST_STEP_FAILURE(ret);
    532	}
    533
    534	ret = write_adi(fd, &version, sizeof(version));
    535	if (ret != sizeof(version))
    536		TEST_STEP_FAILURE(ret);
    537
    538	oret = seek_adi(fd, offset, SEEK_SET);
    539	if (oret != offset) {
    540		ret = -1;
    541		TEST_STEP_FAILURE(ret);
    542	}
    543
    544	ret = read_adi(fd, &version, sizeof(version));
    545	if (ret != sizeof(version))
    546		TEST_STEP_FAILURE(ret);
    547
    548	if (expected_version != version) {
    549		DEBUG_PRINT_L2("\tExpected version %d but read version %d\n",
    550			       expected_version, version);
    551		TEST_STEP_FAILURE(-expected_version);
    552	}
    553
    554	ret = 0;
    555out:
    556	RETURN_FROM_TEST(ret);
    557}
    558
    559#define TEST6_VERSION_SZ        9434
    560static int test6_rw_aligned_9434bytes(int fd)
    561{
    562	/* somewhat arbitrarily chosen address */
    563	unsigned long paddr =
    564		(end_addr[range_count - 1] - 0x5F000) & ~(ADI_BLKSZ - 1);
    565	unsigned char version[TEST6_VERSION_SZ],
    566		      expected_version[TEST6_VERSION_SZ];
    567	loff_t offset;
    568	off_t oret;
    569	int ret, i;
    570
    571	offset = paddr / ADI_BLKSZ;
    572	for (i = 0; i < TEST6_VERSION_SZ; i++)
    573		version[i] = expected_version[i] = random_version();
    574
    575	oret = seek_adi(fd, offset, SEEK_SET);
    576	if (oret != offset) {
    577		ret = -1;
    578		TEST_STEP_FAILURE(ret);
    579	}
    580
    581	ret = write_adi(fd, version, sizeof(version));
    582	if (ret != sizeof(version))
    583		TEST_STEP_FAILURE(ret);
    584
    585	memset(version, 0, TEST6_VERSION_SZ);
    586
    587	oret = seek_adi(fd, offset, SEEK_SET);
    588	if (oret != offset) {
    589		ret = -1;
    590		TEST_STEP_FAILURE(ret);
    591	}
    592
    593	ret = read_adi(fd, version, sizeof(version));
    594	if (ret != sizeof(version))
    595		TEST_STEP_FAILURE(ret);
    596
    597	for (i = 0; i < TEST6_VERSION_SZ; i++) {
    598		if (expected_version[i] != version[i]) {
    599			DEBUG_PRINT_L2(
    600				"\tExpected version %d but read version %d\n",
    601				expected_version[i], version[i]);
    602			TEST_STEP_FAILURE(-expected_version[i]);
    603		}
    604	}
    605
    606	ret = 0;
    607out:
    608	RETURN_FROM_TEST(ret);
    609}
    610
    611#define TEST7_VERSION_SZ        14963
    612static int test7_rw_aligned_14963bytes(int fd)
    613{
    614	/* somewhat arbitrarily chosen address */
    615	unsigned long paddr =
    616	  ((start_addr[range_count - 1] + 0xF000) & ~(ADI_BLKSZ - 1)) + 39;
    617	unsigned char version[TEST7_VERSION_SZ],
    618		      expected_version[TEST7_VERSION_SZ];
    619	loff_t offset;
    620	off_t oret;
    621	int ret, i;
    622
    623	offset = paddr / ADI_BLKSZ;
    624	for (i = 0; i < TEST7_VERSION_SZ; i++) {
    625		version[i] = random_version();
    626		expected_version[i] = version[i];
    627	}
    628
    629	oret = seek_adi(fd, offset, SEEK_SET);
    630	if (oret != offset) {
    631		ret = -1;
    632		TEST_STEP_FAILURE(ret);
    633	}
    634
    635	ret = write_adi(fd, version, sizeof(version));
    636	if (ret != sizeof(version))
    637		TEST_STEP_FAILURE(ret);
    638
    639	memset(version, 0, TEST7_VERSION_SZ);
    640
    641	oret = seek_adi(fd, offset, SEEK_SET);
    642	if (oret != offset) {
    643		ret = -1;
    644		TEST_STEP_FAILURE(ret);
    645	}
    646
    647	ret = read_adi(fd, version, sizeof(version));
    648	if (ret != sizeof(version))
    649		TEST_STEP_FAILURE(ret);
    650
    651	for (i = 0; i < TEST7_VERSION_SZ; i++) {
    652		if (expected_version[i] != version[i]) {
    653			DEBUG_PRINT_L2(
    654				"\tExpected version %d but read version %d\n",
    655				expected_version[i], version[i]);
    656			TEST_STEP_FAILURE(-expected_version[i]);
    657		}
    658
    659		paddr += ADI_BLKSZ;
    660	}
    661
    662	ret = 0;
    663out:
    664	RETURN_FROM_TEST(ret);
    665}
    666
    667static int (*tests[])(int fd) = {
    668	test0_prpw_aligned_1byte,
    669	test1_prpw_aligned_4096bytes,
    670	test2_prpw_aligned_10327bytes,
    671	test3_prpw_unaligned_12541bytes,
    672	test4_lseek,
    673	test5_rw_aligned_1byte,
    674	test6_rw_aligned_9434bytes,
    675	test7_rw_aligned_14963bytes,
    676};
    677#define TEST_COUNT	ARRAY_SIZE(tests)
    678
    679int main(int argc, char *argv[])
    680{
    681	int fd, ret, test;
    682
    683	ret = build_memory_map();
    684	if (ret < 0)
    685		return ret;
    686
    687	fd = open("/dev/adi", O_RDWR);
    688	if (fd < 0) {
    689		fprintf(stderr, "open: error %d: %s\n",
    690			errno, strerror(errno));
    691		return -errno;
    692	}
    693
    694	for (test = 0; test < TEST_COUNT; test++) {
    695		DEBUG_PRINT_L1("Running test #%d\n", test);
    696
    697		ret = (*tests[test])(fd);
    698		if (ret != 0)
    699			ksft_test_result_fail("Test #%d failed: error %d\n",
    700					      test, ret);
    701		else
    702			ksft_test_result_pass("Test #%d passed\n", test);
    703	}
    704
    705	print_stats();
    706	close(fd);
    707
    708	if (ksft_get_fail_cnt() > 0)
    709		ksft_exit_fail();
    710	else
    711		ksft_exit_pass();
    712
    713	/* it's impossible to get here, but the compiler throws a warning
    714	 * about control reaching the end of non-void function.  bah.
    715	 */
    716	return 0;
    717}