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

testusb.c (12395B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* $(CROSS_COMPILE)cc -Wall -Wextra -g -lpthread -o testusb testusb.c */
      3
      4/*
      5 * Copyright (c) 2002 by David Brownell
      6 * Copyright (c) 2010 by Samsung Electronics
      7 * Author: Michal Nazarewicz <mina86@mina86.com>
      8 */
      9
     10/*
     11 * This program issues ioctls to perform the tests implemented by the
     12 * kernel driver.  It can generate a variety of transfer patterns; you
     13 * should make sure to test both regular streaming and mixes of
     14 * transfer sizes (including short transfers).
     15 *
     16 * For more information on how this can be used and on USB testing
     17 * refer to <URL:http://www.linux-usb.org/usbtest/>.
     18 */
     19
     20#include <stdio.h>
     21#include <string.h>
     22#include <ftw.h>
     23#include <stdlib.h>
     24#include <pthread.h>
     25#include <unistd.h>
     26#include <errno.h>
     27#include <limits.h>
     28
     29#include <sys/types.h>
     30#include <sys/stat.h>
     31#include <fcntl.h>
     32
     33#include <sys/ioctl.h>
     34#include <linux/usbdevice_fs.h>
     35
     36/*-------------------------------------------------------------------------*/
     37
     38#define	TEST_CASES	30
     39
     40// FIXME make these public somewhere; usbdevfs.h?
     41
     42struct usbtest_param {
     43	// inputs
     44	unsigned		test_num;	/* 0..(TEST_CASES-1) */
     45	unsigned		iterations;
     46	unsigned		length;
     47	unsigned		vary;
     48	unsigned		sglen;
     49
     50	// outputs
     51	struct timeval		duration;
     52};
     53#define USBTEST_REQUEST	_IOWR('U', 100, struct usbtest_param)
     54
     55/*-------------------------------------------------------------------------*/
     56
     57/* #include <linux/usb_ch9.h> */
     58
     59#define USB_DT_DEVICE			0x01
     60#define USB_DT_INTERFACE		0x04
     61
     62#define USB_CLASS_PER_INTERFACE		0	/* for DeviceClass */
     63#define USB_CLASS_VENDOR_SPEC		0xff
     64
     65
     66struct usb_device_descriptor {
     67	__u8  bLength;
     68	__u8  bDescriptorType;
     69	__u16 bcdUSB;
     70	__u8  bDeviceClass;
     71	__u8  bDeviceSubClass;
     72	__u8  bDeviceProtocol;
     73	__u8  bMaxPacketSize0;
     74	__u16 idVendor;
     75	__u16 idProduct;
     76	__u16 bcdDevice;
     77	__u8  iManufacturer;
     78	__u8  iProduct;
     79	__u8  iSerialNumber;
     80	__u8  bNumConfigurations;
     81} __attribute__ ((packed));
     82
     83struct usb_interface_descriptor {
     84	__u8  bLength;
     85	__u8  bDescriptorType;
     86
     87	__u8  bInterfaceNumber;
     88	__u8  bAlternateSetting;
     89	__u8  bNumEndpoints;
     90	__u8  bInterfaceClass;
     91	__u8  bInterfaceSubClass;
     92	__u8  bInterfaceProtocol;
     93	__u8  iInterface;
     94} __attribute__ ((packed));
     95
     96enum usb_device_speed {
     97	USB_SPEED_UNKNOWN = 0,			/* enumerating */
     98	USB_SPEED_LOW, USB_SPEED_FULL,		/* usb 1.1 */
     99	USB_SPEED_HIGH				/* usb 2.0 */
    100};
    101
    102/*-------------------------------------------------------------------------*/
    103
    104static char *speed (enum usb_device_speed s)
    105{
    106	switch (s) {
    107	case USB_SPEED_UNKNOWN:	return "unknown";
    108	case USB_SPEED_LOW:	return "low";
    109	case USB_SPEED_FULL:	return "full";
    110	case USB_SPEED_HIGH:	return "high";
    111	default:		return "??";
    112	}
    113}
    114
    115struct testdev {
    116	struct testdev		*next;
    117	char			*name;
    118	pthread_t		thread;
    119	enum usb_device_speed	speed;
    120	unsigned		ifnum : 8;
    121	unsigned		forever : 1;
    122	int			test;
    123
    124	struct usbtest_param	param;
    125};
    126static struct testdev		*testdevs;
    127
    128static int testdev_ffs_ifnum(FILE *fd)
    129{
    130	union {
    131		char buf[255];
    132		struct usb_interface_descriptor intf;
    133	} u;
    134
    135	for (;;) {
    136		if (fread(u.buf, 1, 1, fd) != 1)
    137			return -1;
    138		if (fread(u.buf + 1, (unsigned char)u.buf[0] - 1, 1, fd) != 1)
    139			return -1;
    140
    141		if (u.intf.bLength == sizeof u.intf
    142		 && u.intf.bDescriptorType == USB_DT_INTERFACE
    143		 && u.intf.bNumEndpoints == 2
    144		 && u.intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC
    145		 && u.intf.bInterfaceSubClass == 0
    146		 && u.intf.bInterfaceProtocol == 0)
    147			return (unsigned char)u.intf.bInterfaceNumber;
    148	}
    149}
    150
    151static int testdev_ifnum(FILE *fd)
    152{
    153	struct usb_device_descriptor dev;
    154
    155	if (fread(&dev, sizeof dev, 1, fd) != 1)
    156		return -1;
    157
    158	if (dev.bLength != sizeof dev || dev.bDescriptorType != USB_DT_DEVICE)
    159		return -1;
    160
    161	/* FX2 with (tweaked) bulksrc firmware */
    162	if (dev.idVendor == 0x0547 && dev.idProduct == 0x1002)
    163		return 0;
    164
    165	/*----------------------------------------------------*/
    166
    167	/* devices that start up using the EZ-USB default device and
    168	 * which we can use after loading simple firmware.  hotplug
    169	 * can fxload it, and then run this test driver.
    170	 *
    171	 * we return false positives in two cases:
    172	 * - the device has a "real" driver (maybe usb-serial) that
    173	 *   renumerates.  the device should vanish quickly.
    174	 * - the device doesn't have the test firmware installed.
    175	 */
    176
    177	/* generic EZ-USB FX controller */
    178	if (dev.idVendor == 0x0547 && dev.idProduct == 0x2235)
    179		return 0;
    180
    181	/* generic EZ-USB FX2 controller */
    182	if (dev.idVendor == 0x04b4 && dev.idProduct == 0x8613)
    183		return 0;
    184
    185	/* CY3671 development board with EZ-USB FX */
    186	if (dev.idVendor == 0x0547 && dev.idProduct == 0x0080)
    187		return 0;
    188
    189	/* Keyspan 19Qi uses an21xx (original EZ-USB) */
    190	if (dev.idVendor == 0x06cd && dev.idProduct == 0x010b)
    191		return 0;
    192
    193	/*----------------------------------------------------*/
    194
    195	/* "gadget zero", Linux-USB test software */
    196	if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a0)
    197		return 0;
    198
    199	/* user mode subset of that */
    200	if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a4)
    201		return testdev_ffs_ifnum(fd);
    202		/* return 0; */
    203
    204	/* iso version of usermode code */
    205	if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a3)
    206		return 0;
    207
    208	/* some GPL'd test firmware uses these IDs */
    209
    210	if (dev.idVendor == 0xfff0 && dev.idProduct == 0xfff0)
    211		return 0;
    212
    213	/*----------------------------------------------------*/
    214
    215	/* iBOT2 high speed webcam */
    216	if (dev.idVendor == 0x0b62 && dev.idProduct == 0x0059)
    217		return 0;
    218
    219	/*----------------------------------------------------*/
    220
    221	/* the FunctionFS gadget can have the source/sink interface
    222	 * anywhere.  We look for an interface descriptor that match
    223	 * what we expect.  We ignore configuratiens thou. */
    224
    225	if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4ac
    226	 && (dev.bDeviceClass == USB_CLASS_PER_INTERFACE
    227	  || dev.bDeviceClass == USB_CLASS_VENDOR_SPEC))
    228		return testdev_ffs_ifnum(fd);
    229
    230	return -1;
    231}
    232
    233static int find_testdev(const char *name, const struct stat *sb, int flag)
    234{
    235	FILE				*fd;
    236	int				ifnum;
    237	struct testdev			*entry;
    238
    239	(void)sb; /* unused */
    240
    241	if (flag != FTW_F)
    242		return 0;
    243
    244	fd = fopen(name, "rb");
    245	if (!fd) {
    246		perror(name);
    247		return 0;
    248	}
    249
    250	ifnum = testdev_ifnum(fd);
    251	fclose(fd);
    252	if (ifnum < 0)
    253		return 0;
    254
    255	entry = calloc(1, sizeof *entry);
    256	if (!entry)
    257		goto nomem;
    258
    259	entry->name = strdup(name);
    260	if (!entry->name) {
    261		free(entry);
    262nomem:
    263		perror("malloc");
    264		return 0;
    265	}
    266
    267	entry->ifnum = ifnum;
    268	entry->next = testdevs;
    269	testdevs = entry;
    270	return 0;
    271}
    272
    273static int
    274usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
    275{
    276	struct usbdevfs_ioctl	wrapper;
    277
    278	wrapper.ifno = ifno;
    279	wrapper.ioctl_code = request;
    280	wrapper.data = param;
    281
    282	return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
    283}
    284
    285static void *handle_testdev (void *arg)
    286{
    287	struct testdev		*dev = arg;
    288	int			fd, i;
    289	int			status;
    290
    291	if ((fd = open (dev->name, O_RDWR)) < 0) {
    292		perror ("can't open dev file r/w");
    293		return 0;
    294	}
    295
    296	status  =  ioctl(fd, USBDEVFS_GET_SPEED, NULL);
    297	if (status < 0)
    298		fprintf(stderr, "USBDEVFS_GET_SPEED failed %d\n", status);
    299	else
    300		dev->speed = status;
    301	fprintf(stderr, "%s speed\t%s\t%u\n",
    302			speed(dev->speed), dev->name, dev->ifnum);
    303
    304restart:
    305	for (i = 0; i < TEST_CASES; i++) {
    306		if (dev->test != -1 && dev->test != i)
    307			continue;
    308		dev->param.test_num = i;
    309
    310		status = usbdev_ioctl (fd, dev->ifnum,
    311				USBTEST_REQUEST, &dev->param);
    312		if (status < 0 && errno == EOPNOTSUPP)
    313			continue;
    314
    315		/* FIXME need a "syslog it" option for background testing */
    316
    317		/* NOTE: each thread emits complete lines; no fragments! */
    318		if (status < 0) {
    319			char	buf [80];
    320			int	err = errno;
    321
    322			if (strerror_r (errno, buf, sizeof buf)) {
    323				snprintf (buf, sizeof buf, "error %d", err);
    324				errno = err;
    325			}
    326			printf ("%s test %d --> %d (%s)\n",
    327				dev->name, i, errno, buf);
    328		} else
    329			printf ("%s test %d, %4d.%.06d secs\n", dev->name, i,
    330				(int) dev->param.duration.tv_sec,
    331				(int) dev->param.duration.tv_usec);
    332
    333		fflush (stdout);
    334	}
    335	if (dev->forever)
    336		goto restart;
    337
    338	close (fd);
    339	return arg;
    340}
    341
    342static const char *usb_dir_find(void)
    343{
    344	static char udev_usb_path[] = "/dev/bus/usb";
    345
    346	if (access(udev_usb_path, F_OK) == 0)
    347		return udev_usb_path;
    348
    349	return NULL;
    350}
    351
    352static int parse_num(unsigned *num, const char *str)
    353{
    354	unsigned long val;
    355	char *end;
    356
    357	errno = 0;
    358	val = strtoul(str, &end, 0);
    359	if (errno || *end || val > UINT_MAX)
    360		return -1;
    361	*num = val;
    362	return 0;
    363}
    364
    365int main (int argc, char **argv)
    366{
    367
    368	int			c;
    369	struct testdev		*entry;
    370	char			*device;
    371	const char		*usb_dir = NULL;
    372	int			all = 0, forever = 0, not = 0;
    373	int			test = -1 /* all */;
    374	struct usbtest_param	param;
    375
    376	/* pick defaults that works with all speeds, without short packets.
    377	 *
    378	 * Best per-frame data rates:
    379	 *     super speed,bulk      1024 * 16 * 8 = 131072
    380	 *                 interrupt 1024 *  3 * 8 =  24576
    381	 *     high speed, bulk       512 * 13 * 8 =  53248
    382	 *                 interrupt 1024 *  3 * 8 =  24576
    383	 *     full speed, bulk/intr   64 * 19     =   1216
    384	 *                 interrupt   64 *  1     =     64
    385	 *      low speed, interrupt    8 *  1     =      8
    386	 */
    387	param.iterations = 1000;
    388	param.length = 1024;
    389	param.vary = 1024;
    390	param.sglen = 32;
    391
    392	/* for easy use when hotplugging */
    393	device = getenv ("DEVICE");
    394
    395	while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
    396	switch (c) {
    397	case 'D':	/* device, if only one */
    398		device = optarg;
    399		continue;
    400	case 'A':	/* use all devices with specified USB dir */
    401		usb_dir = optarg;
    402		/* FALL THROUGH */
    403	case 'a':	/* use all devices */
    404		device = NULL;
    405		all = 1;
    406		continue;
    407	case 'c':	/* count iterations */
    408		if (parse_num(&param.iterations, optarg))
    409			goto usage;
    410		continue;
    411	case 'g':	/* scatter/gather entries */
    412		if (parse_num(&param.sglen, optarg))
    413			goto usage;
    414		continue;
    415	case 'l':	/* loop forever */
    416		forever = 1;
    417		continue;
    418	case 'n':	/* no test running! */
    419		not = 1;
    420		continue;
    421	case 's':	/* size of packet */
    422		if (parse_num(&param.length, optarg))
    423			goto usage;
    424		continue;
    425	case 't':	/* run just one test */
    426		test = atoi (optarg);
    427		if (test < 0)
    428			goto usage;
    429		continue;
    430	case 'v':	/* vary packet size by ... */
    431		if (parse_num(&param.vary, optarg))
    432			goto usage;
    433		continue;
    434	case '?':
    435	case 'h':
    436	default:
    437usage:
    438		fprintf (stderr,
    439			"usage: %s [options]\n"
    440			"Options:\n"
    441			"\t-D dev		only test specific device\n"
    442			"\t-A usb-dir\n"
    443			"\t-a		test all recognized devices\n"
    444			"\t-l		loop forever(for stress test)\n"
    445			"\t-t testnum	only run specified case\n"
    446			"\t-n		no test running, show devices to be tested\n"
    447			"Case arguments:\n"
    448			"\t-c iterations		default 1000\n"
    449			"\t-s transfer length	default 1024\n"
    450			"\t-g sglen		default 32\n"
    451			"\t-v vary			default 1024\n",
    452			argv[0]);
    453		return 1;
    454	}
    455	if (optind != argc)
    456		goto usage;
    457	if (!all && !device) {
    458		fprintf (stderr, "must specify '-a' or '-D dev', "
    459			"or DEVICE=/dev/bus/usb/BBB/DDD in env\n");
    460		goto usage;
    461	}
    462
    463	/* Find usb device subdirectory */
    464	if (!usb_dir) {
    465		usb_dir = usb_dir_find();
    466		if (!usb_dir) {
    467			fputs ("USB device files are missing\n", stderr);
    468			return -1;
    469		}
    470	}
    471
    472	/* collect and list the test devices */
    473	if (ftw (usb_dir, find_testdev, 3) != 0) {
    474		fputs ("ftw failed; are USB device files missing?\n", stderr);
    475		return -1;
    476	}
    477
    478	/* quit, run single test, or create test threads */
    479	if (!testdevs && !device) {
    480		fputs ("no test devices recognized\n", stderr);
    481		return -1;
    482	}
    483	if (not)
    484		return 0;
    485	if (testdevs && !testdevs->next && !device)
    486		device = testdevs->name;
    487	for (entry = testdevs; entry; entry = entry->next) {
    488		int	status;
    489
    490		entry->param = param;
    491		entry->forever = forever;
    492		entry->test = test;
    493
    494		if (device) {
    495			if (strcmp (entry->name, device))
    496				continue;
    497			return handle_testdev (entry) != entry;
    498		}
    499		status = pthread_create (&entry->thread, 0, handle_testdev, entry);
    500		if (status)
    501			perror ("pthread_create");
    502	}
    503	if (device) {
    504		struct testdev		dev;
    505
    506		/* kernel can recognize test devices we don't */
    507		fprintf (stderr, "%s: %s may see only control tests\n",
    508				argv [0], device);
    509
    510		memset (&dev, 0, sizeof dev);
    511		dev.name = device;
    512		dev.param = param;
    513		dev.forever = forever;
    514		dev.test = test;
    515		return handle_testdev (&dev) != &dev;
    516	}
    517
    518	/* wait for tests to complete */
    519	for (entry = testdevs; entry; entry = entry->next) {
    520		void	*retval;
    521
    522		if (pthread_join (entry->thread, &retval))
    523			perror ("pthread_join");
    524		/* testing errors discarded! */
    525	}
    526
    527	return 0;
    528}