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_simple.c (9108B)


      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
     52/******************** Descriptors and Strings *******************************/
     53
     54static const struct {
     55	struct usb_functionfs_descs_head_v2 header;
     56	__le32 fs_count;
     57	__le32 hs_count;
     58	struct {
     59		struct usb_interface_descriptor intf;
     60		struct usb_endpoint_descriptor_no_audio bulk_sink;
     61		struct usb_endpoint_descriptor_no_audio bulk_source;
     62	} __attribute__ ((__packed__)) fs_descs, hs_descs;
     63} __attribute__ ((__packed__)) descriptors = {
     64	.header = {
     65		.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
     66		.flags = htole32(FUNCTIONFS_HAS_FS_DESC |
     67				     FUNCTIONFS_HAS_HS_DESC),
     68		.length = htole32(sizeof(descriptors)),
     69	},
     70	.fs_count = htole32(3),
     71	.fs_descs = {
     72		.intf = {
     73			.bLength = sizeof(descriptors.fs_descs.intf),
     74			.bDescriptorType = USB_DT_INTERFACE,
     75			.bNumEndpoints = 2,
     76			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
     77			.iInterface = 1,
     78		},
     79		.bulk_sink = {
     80			.bLength = sizeof(descriptors.fs_descs.bulk_sink),
     81			.bDescriptorType = USB_DT_ENDPOINT,
     82			.bEndpointAddress = 1 | USB_DIR_IN,
     83			.bmAttributes = USB_ENDPOINT_XFER_BULK,
     84		},
     85		.bulk_source = {
     86			.bLength = sizeof(descriptors.fs_descs.bulk_source),
     87			.bDescriptorType = USB_DT_ENDPOINT,
     88			.bEndpointAddress = 2 | USB_DIR_OUT,
     89			.bmAttributes = USB_ENDPOINT_XFER_BULK,
     90		},
     91	},
     92	.hs_count = htole32(3),
     93	.hs_descs = {
     94		.intf = {
     95			.bLength = sizeof(descriptors.hs_descs.intf),
     96			.bDescriptorType = USB_DT_INTERFACE,
     97			.bNumEndpoints = 2,
     98			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
     99			.iInterface = 1,
    100		},
    101		.bulk_sink = {
    102			.bLength = sizeof(descriptors.hs_descs.bulk_sink),
    103			.bDescriptorType = USB_DT_ENDPOINT,
    104			.bEndpointAddress = 1 | USB_DIR_IN,
    105			.bmAttributes = USB_ENDPOINT_XFER_BULK,
    106			.wMaxPacketSize = htole16(512),
    107		},
    108		.bulk_source = {
    109			.bLength = sizeof(descriptors.hs_descs.bulk_source),
    110			.bDescriptorType = USB_DT_ENDPOINT,
    111			.bEndpointAddress = 2 | USB_DIR_OUT,
    112			.bmAttributes = USB_ENDPOINT_XFER_BULK,
    113			.wMaxPacketSize = htole16(512),
    114		},
    115	},
    116};
    117
    118#define STR_INTERFACE "AIO Test"
    119
    120static const struct {
    121	struct usb_functionfs_strings_head header;
    122	struct {
    123		__le16 code;
    124		const char str1[sizeof(STR_INTERFACE)];
    125	} __attribute__ ((__packed__)) lang0;
    126} __attribute__ ((__packed__)) strings = {
    127	.header = {
    128		.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
    129		.length = htole32(sizeof(strings)),
    130		.str_count = htole32(1),
    131		.lang_count = htole32(1),
    132	},
    133	.lang0 = {
    134		htole16(0x0409), /* en-us */
    135		STR_INTERFACE,
    136	},
    137};
    138
    139/******************** Endpoints handling *******************************/
    140
    141static void display_event(struct usb_functionfs_event *event)
    142{
    143	static const char *const names[] = {
    144		[FUNCTIONFS_BIND] = "BIND",
    145		[FUNCTIONFS_UNBIND] = "UNBIND",
    146		[FUNCTIONFS_ENABLE] = "ENABLE",
    147		[FUNCTIONFS_DISABLE] = "DISABLE",
    148		[FUNCTIONFS_SETUP] = "SETUP",
    149		[FUNCTIONFS_SUSPEND] = "SUSPEND",
    150		[FUNCTIONFS_RESUME] = "RESUME",
    151	};
    152	switch (event->type) {
    153	case FUNCTIONFS_BIND:
    154	case FUNCTIONFS_UNBIND:
    155	case FUNCTIONFS_ENABLE:
    156	case FUNCTIONFS_DISABLE:
    157	case FUNCTIONFS_SETUP:
    158	case FUNCTIONFS_SUSPEND:
    159	case FUNCTIONFS_RESUME:
    160		printf("Event %s\n", names[event->type]);
    161	}
    162}
    163
    164static void handle_ep0(int ep0, bool *ready)
    165{
    166	struct usb_functionfs_event event;
    167	int ret;
    168
    169	struct pollfd pfds[1];
    170	pfds[0].fd = ep0;
    171	pfds[0].events = POLLIN;
    172
    173	ret = poll(pfds, 1, 0);
    174
    175	if (ret && (pfds[0].revents & POLLIN)) {
    176		ret = read(ep0, &event, sizeof(event));
    177		if (!ret) {
    178			perror("unable to read event from ep0");
    179			return;
    180		}
    181		display_event(&event);
    182		switch (event.type) {
    183		case FUNCTIONFS_SETUP:
    184			if (event.u.setup.bRequestType & USB_DIR_IN)
    185				write(ep0, NULL, 0);
    186			else
    187				read(ep0, NULL, 0);
    188			break;
    189
    190		case FUNCTIONFS_ENABLE:
    191			*ready = true;
    192			break;
    193
    194		case FUNCTIONFS_DISABLE:
    195			*ready = false;
    196			break;
    197
    198		default:
    199			break;
    200		}
    201	}
    202}
    203
    204int main(int argc, char *argv[])
    205{
    206	int i, ret;
    207	char *ep_path;
    208
    209	int ep0;
    210	int ep[2];
    211
    212	io_context_t ctx;
    213
    214	int evfd;
    215	fd_set rfds;
    216
    217	char *buf_in, *buf_out;
    218	struct iocb *iocb_in, *iocb_out;
    219	int req_in = 0, req_out = 0;
    220	bool ready;
    221
    222	if (argc != 2) {
    223		printf("ffs directory not specified!\n");
    224		return 1;
    225	}
    226
    227	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
    228	if (!ep_path) {
    229		perror("malloc");
    230		return 1;
    231	}
    232
    233	/* open endpoint files */
    234	sprintf(ep_path, "%s/ep0", argv[1]);
    235	ep0 = open(ep_path, O_RDWR);
    236	if (ep0 < 0) {
    237		perror("unable to open ep0");
    238		return 1;
    239	}
    240	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
    241		perror("unable do write descriptors");
    242		return 1;
    243	}
    244	if (write(ep0, &strings, sizeof(strings)) < 0) {
    245		perror("unable to write strings");
    246		return 1;
    247	}
    248	for (i = 0; i < 2; ++i) {
    249		sprintf(ep_path, "%s/ep%d", argv[1], i+1);
    250		ep[i] = open(ep_path, O_RDWR);
    251		if (ep[i] < 0) {
    252			printf("unable to open ep%d: %s\n", i+1,
    253			       strerror(errno));
    254			return 1;
    255		}
    256	}
    257
    258	free(ep_path);
    259
    260	memset(&ctx, 0, sizeof(ctx));
    261	/* setup aio context to handle up to 2 requests */
    262	if (io_setup(2, &ctx) < 0) {
    263		perror("unable to setup aio");
    264		return 1;
    265	}
    266
    267	evfd = eventfd(0, 0);
    268	if (evfd < 0) {
    269		perror("unable to open eventfd");
    270		return 1;
    271	}
    272
    273	/* alloc buffers and requests */
    274	buf_in = malloc(BUF_LEN);
    275	buf_out = malloc(BUF_LEN);
    276	iocb_in = malloc(sizeof(*iocb_in));
    277	iocb_out = malloc(sizeof(*iocb_out));
    278
    279	while (1) {
    280		FD_ZERO(&rfds);
    281		FD_SET(ep0, &rfds);
    282		FD_SET(evfd, &rfds);
    283
    284		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
    285			     &rfds, NULL, NULL, NULL);
    286		if (ret < 0) {
    287			if (errno == EINTR)
    288				continue;
    289			perror("select");
    290			break;
    291		}
    292
    293		if (FD_ISSET(ep0, &rfds))
    294			handle_ep0(ep0, &ready);
    295
    296		/* we are waiting for function ENABLE */
    297		if (!ready)
    298			continue;
    299
    300		/* if something was submitted we wait for event */
    301		if (FD_ISSET(evfd, &rfds)) {
    302			uint64_t ev_cnt;
    303			ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
    304			if (ret < 0) {
    305				perror("unable to read eventfd");
    306				break;
    307			}
    308
    309			struct io_event e[2];
    310			/* we wait for one event */
    311			ret = io_getevents(ctx, 1, 2, e, NULL);
    312			/* if we got event */
    313			for (i = 0; i < ret; ++i) {
    314				if (e[i].obj->aio_fildes == ep[0]) {
    315					printf("ev=in; ret=%lu\n", e[i].res);
    316					req_in = 0;
    317				} else if (e[i].obj->aio_fildes == ep[1]) {
    318					printf("ev=out; ret=%lu\n", e[i].res);
    319					req_out = 0;
    320				}
    321			}
    322		}
    323
    324		if (!req_in) { /* if IN transfer not requested*/
    325			/* prepare write request */
    326			io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
    327			/* enable eventfd notification */
    328			iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
    329			iocb_in->u.c.resfd = evfd;
    330			/* submit table of requests */
    331			ret = io_submit(ctx, 1, &iocb_in);
    332			if (ret >= 0) { /* if ret > 0 request is queued */
    333				req_in = 1;
    334				printf("submit: in\n");
    335			} else
    336				perror("unable to submit request");
    337		}
    338		if (!req_out) { /* if OUT transfer not requested */
    339			/* prepare read request */
    340			io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
    341			/* enable eventfs notification */
    342			iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
    343			iocb_out->u.c.resfd = evfd;
    344			/* submit table of requests */
    345			ret = io_submit(ctx, 1, &iocb_out);
    346			if (ret >= 0) { /* if ret > 0 request is queued */
    347				req_out = 1;
    348				printf("submit: out\n");
    349			} else
    350				perror("unable to submit request");
    351		}
    352	}
    353
    354	/* free resources */
    355
    356	io_destroy(ctx);
    357
    358	free(buf_in);
    359	free(buf_out);
    360	free(iocb_in);
    361	free(iocb_out);
    362
    363	for (i = 0; i < 2; ++i)
    364		close(ep[i]);
    365	close(ep0);
    366
    367	return 0;
    368}