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

aio_multibuff.c (9268B)


      1/*
      2 * This is free and unencumbered software released into the public domain.
      3 *
      4 * Anyone is free to copy, modify, publish, use, compile, sell, or
      5 * distribute this software, either in source code form or as a compiled
      6 * binary, for any purpose, commercial or non-commercial, and by any
      7 * means.
      8 *
      9 * In jurisdictions that recognize copyright laws, the author or authors
     10 * of this software dedicate any and all copyright interest in the
     11 * software to the public domain. We make this dedication for the benefit
     12 * of the public at large and to the detriment of our heirs and
     13 * successors. We intend this dedication to be an overt act of
     14 * relinquishment in perpetuity of all present and future rights to this
     15 * software under copyright law.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23 * OTHER DEALINGS IN THE SOFTWARE.
     24 *
     25 * For more information, please refer to <http://unlicense.org/>
     26 */
     27
     28#define _BSD_SOURCE /* for endian.h */
     29
     30#include <endian.h>
     31#include <errno.h>
     32#include <fcntl.h>
     33#include <stdarg.h>
     34#include <stdio.h>
     35#include <stdlib.h>
     36#include <string.h>
     37#include <sys/ioctl.h>
     38#include <sys/stat.h>
     39#include <sys/types.h>
     40#include <sys/poll.h>
     41#include <unistd.h>
     42#include <stdbool.h>
     43#include <sys/eventfd.h>
     44
     45#include "libaio.h"
     46#define IOCB_FLAG_RESFD         (1 << 0)
     47
     48#include <linux/usb/functionfs.h>
     49
     50#define BUF_LEN		8192
     51#define BUFS_MAX	128
     52#define AIO_MAX		(BUFS_MAX*2)
     53
     54/******************** Descriptors and Strings *******************************/
     55
     56static const struct {
     57	struct usb_functionfs_descs_head_v2 header;
     58	__le32 fs_count;
     59	__le32 hs_count;
     60	struct {
     61		struct usb_interface_descriptor intf;
     62		struct usb_endpoint_descriptor_no_audio bulk_sink;
     63		struct usb_endpoint_descriptor_no_audio bulk_source;
     64	} __attribute__ ((__packed__)) fs_descs, hs_descs;
     65} __attribute__ ((__packed__)) descriptors = {
     66	.header = {
     67		.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
     68		.flags = htole32(FUNCTIONFS_HAS_FS_DESC |
     69				     FUNCTIONFS_HAS_HS_DESC),
     70		.length = htole32(sizeof(descriptors)),
     71	},
     72	.fs_count = htole32(3),
     73	.fs_descs = {
     74		.intf = {
     75			.bLength = sizeof(descriptors.fs_descs.intf),
     76			.bDescriptorType = USB_DT_INTERFACE,
     77			.bNumEndpoints = 2,
     78			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
     79			.iInterface = 1,
     80		},
     81		.bulk_sink = {
     82			.bLength = sizeof(descriptors.fs_descs.bulk_sink),
     83			.bDescriptorType = USB_DT_ENDPOINT,
     84			.bEndpointAddress = 1 | USB_DIR_IN,
     85			.bmAttributes = USB_ENDPOINT_XFER_BULK,
     86		},
     87		.bulk_source = {
     88			.bLength = sizeof(descriptors.fs_descs.bulk_source),
     89			.bDescriptorType = USB_DT_ENDPOINT,
     90			.bEndpointAddress = 2 | USB_DIR_OUT,
     91			.bmAttributes = USB_ENDPOINT_XFER_BULK,
     92		},
     93	},
     94	.hs_count = htole32(3),
     95	.hs_descs = {
     96		.intf = {
     97			.bLength = sizeof(descriptors.hs_descs.intf),
     98			.bDescriptorType = USB_DT_INTERFACE,
     99			.bNumEndpoints = 2,
    100			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
    101			.iInterface = 1,
    102		},
    103		.bulk_sink = {
    104			.bLength = sizeof(descriptors.hs_descs.bulk_sink),
    105			.bDescriptorType = USB_DT_ENDPOINT,
    106			.bEndpointAddress = 1 | USB_DIR_IN,
    107			.bmAttributes = USB_ENDPOINT_XFER_BULK,
    108			.wMaxPacketSize = htole16(512),
    109		},
    110		.bulk_source = {
    111			.bLength = sizeof(descriptors.hs_descs.bulk_source),
    112			.bDescriptorType = USB_DT_ENDPOINT,
    113			.bEndpointAddress = 2 | USB_DIR_OUT,
    114			.bmAttributes = USB_ENDPOINT_XFER_BULK,
    115			.wMaxPacketSize = htole16(512),
    116		},
    117	},
    118};
    119
    120#define STR_INTERFACE "AIO Test"
    121
    122static const struct {
    123	struct usb_functionfs_strings_head header;
    124	struct {
    125		__le16 code;
    126		const char str1[sizeof(STR_INTERFACE)];
    127	} __attribute__ ((__packed__)) lang0;
    128} __attribute__ ((__packed__)) strings = {
    129	.header = {
    130		.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
    131		.length = htole32(sizeof(strings)),
    132		.str_count = htole32(1),
    133		.lang_count = htole32(1),
    134	},
    135	.lang0 = {
    136		htole16(0x0409), /* en-us */
    137		STR_INTERFACE,
    138	},
    139};
    140
    141/********************** Buffer structure *******************************/
    142
    143struct io_buffer {
    144	struct iocb **iocb;
    145	unsigned char **buf;
    146	unsigned cnt;
    147	unsigned len;
    148	unsigned requested;
    149};
    150
    151/******************** Endpoints handling *******************************/
    152
    153static void display_event(struct usb_functionfs_event *event)
    154{
    155	static const char *const names[] = {
    156		[FUNCTIONFS_BIND] = "BIND",
    157		[FUNCTIONFS_UNBIND] = "UNBIND",
    158		[FUNCTIONFS_ENABLE] = "ENABLE",
    159		[FUNCTIONFS_DISABLE] = "DISABLE",
    160		[FUNCTIONFS_SETUP] = "SETUP",
    161		[FUNCTIONFS_SUSPEND] = "SUSPEND",
    162		[FUNCTIONFS_RESUME] = "RESUME",
    163	};
    164	switch (event->type) {
    165	case FUNCTIONFS_BIND:
    166	case FUNCTIONFS_UNBIND:
    167	case FUNCTIONFS_ENABLE:
    168	case FUNCTIONFS_DISABLE:
    169	case FUNCTIONFS_SETUP:
    170	case FUNCTIONFS_SUSPEND:
    171	case FUNCTIONFS_RESUME:
    172		printf("Event %s\n", names[event->type]);
    173	}
    174}
    175
    176static void handle_ep0(int ep0, bool *ready)
    177{
    178	int ret;
    179	struct usb_functionfs_event event;
    180
    181	ret = read(ep0, &event, sizeof(event));
    182	if (!ret) {
    183		perror("unable to read event from ep0");
    184		return;
    185	}
    186	display_event(&event);
    187	switch (event.type) {
    188	case FUNCTIONFS_SETUP:
    189		if (event.u.setup.bRequestType & USB_DIR_IN)
    190			write(ep0, NULL, 0);
    191		else
    192			read(ep0, NULL, 0);
    193		break;
    194
    195	case FUNCTIONFS_ENABLE:
    196		*ready = true;
    197		break;
    198
    199	case FUNCTIONFS_DISABLE:
    200		*ready = false;
    201		break;
    202
    203	default:
    204		break;
    205	}
    206}
    207
    208void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
    209{
    210	unsigned i;
    211	iobuf->buf = malloc(n*sizeof(*iobuf->buf));
    212	iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
    213	iobuf->cnt = n;
    214	iobuf->len = len;
    215	iobuf->requested = 0;
    216	for (i = 0; i < n; ++i) {
    217		iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
    218		iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
    219	}
    220	iobuf->cnt = n;
    221}
    222
    223void delete_bufs(struct io_buffer *iobuf)
    224{
    225	unsigned i;
    226	for (i = 0; i < iobuf->cnt; ++i) {
    227		free(iobuf->buf[i]);
    228		free(iobuf->iocb[i]);
    229	}
    230	free(iobuf->buf);
    231	free(iobuf->iocb);
    232}
    233
    234int main(int argc, char *argv[])
    235{
    236	int ret;
    237	unsigned i, j;
    238	char *ep_path;
    239
    240	int ep0, ep1;
    241
    242	io_context_t ctx;
    243
    244	int evfd;
    245	fd_set rfds;
    246
    247	struct io_buffer iobuf[2];
    248	int actual = 0;
    249	bool ready;
    250
    251	if (argc != 2) {
    252		printf("ffs directory not specified!\n");
    253		return 1;
    254	}
    255
    256	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
    257	if (!ep_path) {
    258		perror("malloc");
    259		return 1;
    260	}
    261
    262	/* open endpoint files */
    263	sprintf(ep_path, "%s/ep0", argv[1]);
    264	ep0 = open(ep_path, O_RDWR);
    265	if (ep0 < 0) {
    266		perror("unable to open ep0");
    267		return 1;
    268	}
    269	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
    270		perror("unable do write descriptors");
    271		return 1;
    272	}
    273	if (write(ep0, &strings, sizeof(strings)) < 0) {
    274		perror("unable to write strings");
    275		return 1;
    276	}
    277	sprintf(ep_path, "%s/ep1", argv[1]);
    278	ep1 = open(ep_path, O_RDWR);
    279	if (ep1 < 0) {
    280		perror("unable to open ep1");
    281		return 1;
    282	}
    283
    284	free(ep_path);
    285
    286	memset(&ctx, 0, sizeof(ctx));
    287	/* setup aio context to handle up to AIO_MAX requests */
    288	if (io_setup(AIO_MAX, &ctx) < 0) {
    289		perror("unable to setup aio");
    290		return 1;
    291	}
    292
    293	evfd = eventfd(0, 0);
    294	if (evfd < 0) {
    295		perror("unable to open eventfd");
    296		return 1;
    297	}
    298
    299	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
    300		init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
    301
    302	while (1) {
    303		FD_ZERO(&rfds);
    304		FD_SET(ep0, &rfds);
    305		FD_SET(evfd, &rfds);
    306
    307		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
    308			     &rfds, NULL, NULL, NULL);
    309		if (ret < 0) {
    310			if (errno == EINTR)
    311				continue;
    312			perror("select");
    313			break;
    314		}
    315
    316		if (FD_ISSET(ep0, &rfds))
    317			handle_ep0(ep0, &ready);
    318
    319		/* we are waiting for function ENABLE */
    320		if (!ready)
    321			continue;
    322
    323		/*
    324		 * when we're preparing new data to submit,
    325		 * second buffer being transmitted
    326		 */
    327		for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
    328			if (iobuf[i].requested)
    329				continue;
    330			/* prepare requests */
    331			for (j = 0; j < iobuf[i].cnt; ++j) {
    332				io_prep_pwrite(iobuf[i].iocb[j], ep1,
    333					       iobuf[i].buf[j],
    334					       iobuf[i].len, 0);
    335				/* enable eventfd notification */
    336				iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
    337				iobuf[i].iocb[j]->u.c.resfd = evfd;
    338			}
    339			/* submit table of requests */
    340			ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
    341			if (ret >= 0) {
    342				iobuf[i].requested = ret;
    343				printf("submit: %d requests buf: %d\n", ret, i);
    344			} else
    345				perror("unable to submit requests");
    346		}
    347
    348		/* if event is ready to read */
    349		if (!FD_ISSET(evfd, &rfds))
    350			continue;
    351
    352		uint64_t ev_cnt;
    353		ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
    354		if (ret < 0) {
    355			perror("unable to read eventfd");
    356			break;
    357		}
    358
    359		struct io_event e[BUFS_MAX];
    360		/* we read aio events */
    361		ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
    362		if (ret > 0) /* if we got events */
    363			iobuf[actual].requested -= ret;
    364
    365		/* if all req's from iocb completed */
    366		if (!iobuf[actual].requested)
    367			actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
    368	}
    369
    370	/* free resources */
    371
    372	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
    373		delete_bufs(&iobuf[i]);
    374	io_destroy(ctx);
    375
    376	close(ep1);
    377	close(ep0);
    378
    379	return 0;
    380}