aboutsummaryrefslogtreecommitdiff
path: root/src/userspace_io.c
blob: 46fc21b278d0b00b74c31a936f0ef786a7d61ceb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <endian.h>
#include <stdlib.h>
#include <errno.h>

#include <arpa/inet.h>

#include <sys/ioctl.h>
#include <sys/mman.h>

#include <linux/vfio.h>

/* Us */
#include <drivers/driver_ops.h>
#include <vfio_api.h>
#include <mm_api.h>
#include <common.h>

/* FIXME modularize driver load */
extern const struct driver_ops r8169_ops;
extern const struct driver_ops e1000e_ops;

const static char help_msg[] = {
	"\n"
	" -d: device uuid\n"
	" -i: device id in /dev/vfio\n"
};

static void usage(char *name)
{
	printf("usage: %s [OPTIONS] \n%s\n", name, help_msg);
}

/* Primitive module loader TODO add items on list? */
static const struct _name_to_ops supported_drivers[] = {
	{ &r8169_ops, "r8169" },
	{ &e1000e_ops, "e1000e" },
	{ NULL, "None" }
};

static const struct driver_ops *ops_from_str(const struct _name_to_ops *table,
					     const char *s)
{
	const struct _name_to_ops *cur;

	for (cur = table; cur->ops; cur++)
		if (!strcasecmp(cur->s, s))
			return cur->ops;

	printf("Invalid driver name\n");
	printf("Valid drivers:\n");
	for (cur = table; cur->ops; cur++)
		printf("    %s\n", cur->s);

	return NULL;
}

static const struct driver_ops *get_ops_fromname(const char *s)
{
	        return ops_from_str(supported_drivers, s);
}

int main(int argc, char *argv[])
{
	struct vfio_group_status group_status = { .argsz = sizeof(group_status) };
	struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) };
	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
	struct vfio_region_info region_info = { .argsz = sizeof(region_info) };
	struct iomem rx_data;
	struct iomem tx_data;
	const struct driver_ops *exec_ops = NULL;
	void *iobase, *iocur, *rxring, *txring, *mmio;
	int container = -1, group = -1, device = -1;
	int ret, c, group_id;
	char group_uuid[64]; /* 37 should be enough */
	char drv_name[64];
	volatile char *rx_buff[256];
	__u32 opts = 0;

	memset(group_uuid, 0, sizeof(group_uuid));
	memset(drv_name, 0, sizeof(drv_name));

	while ((c = getopt(argc, argv, "d:i:n:")) != -1) {
		switch (c) {
		case 'd':
			if (strlen(optarg) >= sizeof(group_uuid))
				break;
			strncpy(group_uuid, optarg, sizeof(group_uuid));
			opts |= OPT_UUID;
			break;
		case 'i':
			group_id = atoi(optarg);
			opts |= OPT_DEV;
			break;
		case 'n':
			/* TODO: get the drv_name from sysfs by ifname */
			if (strlen(optarg) >= sizeof(drv_name))
				break;
			strncpy(drv_name, optarg, sizeof(drv_name));
			break;
		}
	}

	exec_ops = get_ops_fromname(drv_name);
	if (!exec_ops)
		return -EINVAL;

	if ((opts & (OPT_UUID | OPT_DEV)) != (OPT_UUID | OPT_DEV)) {
		usage(argv[0]);
		return -EINVAL;
	}

	iobase = iomem_init();
	if (!iobase)
		return -ENOMEM;
	iocur = iobase;

	/* Create a new container */
	container = get_container();
	if (container < 0)
		goto out;

	group = get_group(group_id);
	if (group < 0)
		goto out;

	device = vfio_init_dev(group, container, &group_status, &iommu_info,
			       &device_info, group_uuid);

	mmio = uio_map_mmio(exec_ops, device);
	if (!mmio) {
		printf("Cannot map MMIO\n");
		goto out;
	}
	/* XXX FIXME check pointers and munmap properly */
	rxring = vfio_mmap_region(device, VFIO_PCI_NUM_REGIONS + 2);
	if (!rxring) {
		printf("Cannot map RxRing\n");
		goto out;
	}
	txring = vfio_mmap_region(device, VFIO_PCI_NUM_REGIONS + 3);
	if (!txring) {
		printf("Cannot map TxRing\n");
		goto out;
	}

	/* FIXME decide on allocated areas, instead of getting 2MB per direction */
	ret = iomem_alloc(device, 2 * 1024 * 1024, &iocur, &rx_data);
	if (ret)
		goto out;

	ret = iomem_alloc(device, 2 * 1024 * 1024, &iocur, &tx_data);
	if (ret)
		goto out;

	if (uio_rx_fill(exec_ops, device, rxring, rx_data, rx_buff, mmio) != 0) {
		printf("Could not fill RxRing\n");
		goto out;
	}

	ioctl(device, 500, NULL);

	// usleep(30 * 1000 * 1000);

	uio_xmit(exec_ops, txring, tx_data, mmio);
	uio_recv(exec_ops, rxring, rx_buff, mmio);

out:
	/* FIXME munmap and release properly on fails */
	//if (rxring)
		//munmap(rxring, region_info.size);
	if (group)
		close(group);
	if (container)
		close(container);
	return -1;
}