xref: /kvmtool/vfio/core.c (revision 6078a4548cfdca42c766c67947986c90310a8546)
1*6078a454SJean-Philippe Brucker #include "kvm/kvm.h"
2*6078a454SJean-Philippe Brucker #include "kvm/vfio.h"
3*6078a454SJean-Philippe Brucker 
4*6078a454SJean-Philippe Brucker #include <linux/list.h>
5*6078a454SJean-Philippe Brucker 
6*6078a454SJean-Philippe Brucker #define VFIO_DEV_DIR		"/dev/vfio"
7*6078a454SJean-Philippe Brucker #define VFIO_DEV_NODE		VFIO_DEV_DIR "/vfio"
8*6078a454SJean-Philippe Brucker #define IOMMU_GROUP_DIR		"/sys/kernel/iommu_groups"
9*6078a454SJean-Philippe Brucker 
10*6078a454SJean-Philippe Brucker static int vfio_container;
11*6078a454SJean-Philippe Brucker static LIST_HEAD(vfio_groups);
12*6078a454SJean-Philippe Brucker static struct vfio_device *vfio_devices;
13*6078a454SJean-Philippe Brucker 
14*6078a454SJean-Philippe Brucker static int vfio_device_pci_parser(const struct option *opt, char *arg,
15*6078a454SJean-Philippe Brucker 				  struct vfio_device_params *dev)
16*6078a454SJean-Philippe Brucker {
17*6078a454SJean-Philippe Brucker 	unsigned int domain, bus, devnr, fn;
18*6078a454SJean-Philippe Brucker 
19*6078a454SJean-Philippe Brucker 	int nr = sscanf(arg, "%4x:%2x:%2x.%1x", &domain, &bus, &devnr, &fn);
20*6078a454SJean-Philippe Brucker 	if (nr < 4) {
21*6078a454SJean-Philippe Brucker 		domain = 0;
22*6078a454SJean-Philippe Brucker 		nr = sscanf(arg, "%2x:%2x.%1x", &bus, &devnr, &fn);
23*6078a454SJean-Philippe Brucker 		if (nr < 3) {
24*6078a454SJean-Philippe Brucker 			pr_err("Invalid device identifier %s", arg);
25*6078a454SJean-Philippe Brucker 			return -EINVAL;
26*6078a454SJean-Philippe Brucker 		}
27*6078a454SJean-Philippe Brucker 	}
28*6078a454SJean-Philippe Brucker 
29*6078a454SJean-Philippe Brucker 	dev->type = VFIO_DEVICE_PCI;
30*6078a454SJean-Philippe Brucker 	dev->bus = "pci";
31*6078a454SJean-Philippe Brucker 	dev->name = malloc(13);
32*6078a454SJean-Philippe Brucker 	if (!dev->name)
33*6078a454SJean-Philippe Brucker 		return -ENOMEM;
34*6078a454SJean-Philippe Brucker 
35*6078a454SJean-Philippe Brucker 	snprintf(dev->name, 13, "%04x:%02x:%02x.%x", domain, bus, devnr, fn);
36*6078a454SJean-Philippe Brucker 
37*6078a454SJean-Philippe Brucker 	return 0;
38*6078a454SJean-Philippe Brucker }
39*6078a454SJean-Philippe Brucker 
40*6078a454SJean-Philippe Brucker int vfio_device_parser(const struct option *opt, const char *arg, int unset)
41*6078a454SJean-Philippe Brucker {
42*6078a454SJean-Philippe Brucker 	int ret = -EINVAL;
43*6078a454SJean-Philippe Brucker 	static int idx = 0;
44*6078a454SJean-Philippe Brucker 	struct kvm *kvm = opt->ptr;
45*6078a454SJean-Philippe Brucker 	struct vfio_device_params *dev, *devs;
46*6078a454SJean-Philippe Brucker 	char *cur, *buf = strdup(arg);
47*6078a454SJean-Philippe Brucker 
48*6078a454SJean-Philippe Brucker 	if (!buf)
49*6078a454SJean-Philippe Brucker 		return -ENOMEM;
50*6078a454SJean-Philippe Brucker 
51*6078a454SJean-Philippe Brucker 	if (idx >= MAX_VFIO_DEVICES) {
52*6078a454SJean-Philippe Brucker 		pr_warning("Too many VFIO devices");
53*6078a454SJean-Philippe Brucker 		goto out_free_buf;
54*6078a454SJean-Philippe Brucker 	}
55*6078a454SJean-Philippe Brucker 
56*6078a454SJean-Philippe Brucker 	devs = realloc(kvm->cfg.vfio_devices, sizeof(*dev) * (idx + 1));
57*6078a454SJean-Philippe Brucker 	if (!devs) {
58*6078a454SJean-Philippe Brucker 		ret = -ENOMEM;
59*6078a454SJean-Philippe Brucker 		goto out_free_buf;
60*6078a454SJean-Philippe Brucker 	}
61*6078a454SJean-Philippe Brucker 
62*6078a454SJean-Philippe Brucker 	kvm->cfg.vfio_devices = devs;
63*6078a454SJean-Philippe Brucker 	dev = &devs[idx];
64*6078a454SJean-Philippe Brucker 
65*6078a454SJean-Philippe Brucker 	cur = strtok(buf, ",");
66*6078a454SJean-Philippe Brucker 	if (!cur)
67*6078a454SJean-Philippe Brucker 		goto out_free_buf;
68*6078a454SJean-Philippe Brucker 
69*6078a454SJean-Philippe Brucker 	if (!strcmp(opt->long_name, "vfio-pci"))
70*6078a454SJean-Philippe Brucker 		ret = vfio_device_pci_parser(opt, cur, dev);
71*6078a454SJean-Philippe Brucker 	else
72*6078a454SJean-Philippe Brucker 		ret = -EINVAL;
73*6078a454SJean-Philippe Brucker 
74*6078a454SJean-Philippe Brucker 	if (!ret)
75*6078a454SJean-Philippe Brucker 		kvm->cfg.num_vfio_devices = ++idx;
76*6078a454SJean-Philippe Brucker 
77*6078a454SJean-Philippe Brucker out_free_buf:
78*6078a454SJean-Philippe Brucker 	free(buf);
79*6078a454SJean-Philippe Brucker 
80*6078a454SJean-Philippe Brucker 	return ret;
81*6078a454SJean-Philippe Brucker }
82*6078a454SJean-Philippe Brucker 
83*6078a454SJean-Philippe Brucker int vfio_map_region(struct kvm *kvm, struct vfio_device *vdev,
84*6078a454SJean-Philippe Brucker 		    struct vfio_region *region)
85*6078a454SJean-Philippe Brucker {
86*6078a454SJean-Philippe Brucker 	void *base;
87*6078a454SJean-Philippe Brucker 	int ret, prot = 0;
88*6078a454SJean-Philippe Brucker 	/* KVM needs page-aligned regions */
89*6078a454SJean-Philippe Brucker 	u64 map_size = ALIGN(region->info.size, PAGE_SIZE);
90*6078a454SJean-Philippe Brucker 
91*6078a454SJean-Philippe Brucker 	/*
92*6078a454SJean-Philippe Brucker 	 * We don't want to mess about trapping config accesses, so require that
93*6078a454SJean-Philippe Brucker 	 * they can be mmap'd. Note that for PCI, this precludes the use of I/O
94*6078a454SJean-Philippe Brucker 	 * BARs in the guest (we will hide them from Configuration Space, which
95*6078a454SJean-Philippe Brucker 	 * is trapped).
96*6078a454SJean-Philippe Brucker 	 */
97*6078a454SJean-Philippe Brucker 	if (!(region->info.flags & VFIO_REGION_INFO_FLAG_MMAP)) {
98*6078a454SJean-Philippe Brucker 		vfio_dev_info(vdev, "ignoring region %u, as it can't be mmap'd",
99*6078a454SJean-Philippe Brucker 			      region->info.index);
100*6078a454SJean-Philippe Brucker 		return 0;
101*6078a454SJean-Philippe Brucker 	}
102*6078a454SJean-Philippe Brucker 
103*6078a454SJean-Philippe Brucker 	if (region->info.flags & VFIO_REGION_INFO_FLAG_READ)
104*6078a454SJean-Philippe Brucker 		prot |= PROT_READ;
105*6078a454SJean-Philippe Brucker 	if (region->info.flags & VFIO_REGION_INFO_FLAG_WRITE)
106*6078a454SJean-Philippe Brucker 		prot |= PROT_WRITE;
107*6078a454SJean-Philippe Brucker 
108*6078a454SJean-Philippe Brucker 	base = mmap(NULL, region->info.size, prot, MAP_SHARED, vdev->fd,
109*6078a454SJean-Philippe Brucker 		    region->info.offset);
110*6078a454SJean-Philippe Brucker 	if (base == MAP_FAILED) {
111*6078a454SJean-Philippe Brucker 		ret = -errno;
112*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to mmap region %u (0x%llx bytes)",
113*6078a454SJean-Philippe Brucker 			     region->info.index, region->info.size);
114*6078a454SJean-Philippe Brucker 		return ret;
115*6078a454SJean-Philippe Brucker 	}
116*6078a454SJean-Philippe Brucker 	region->host_addr = base;
117*6078a454SJean-Philippe Brucker 
118*6078a454SJean-Philippe Brucker 	ret = kvm__register_dev_mem(kvm, region->guest_phys_addr, map_size,
119*6078a454SJean-Philippe Brucker 				    region->host_addr);
120*6078a454SJean-Philippe Brucker 	if (ret) {
121*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to register region with KVM");
122*6078a454SJean-Philippe Brucker 		return ret;
123*6078a454SJean-Philippe Brucker 	}
124*6078a454SJean-Philippe Brucker 
125*6078a454SJean-Philippe Brucker 	return 0;
126*6078a454SJean-Philippe Brucker }
127*6078a454SJean-Philippe Brucker 
128*6078a454SJean-Philippe Brucker void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region)
129*6078a454SJean-Philippe Brucker {
130*6078a454SJean-Philippe Brucker 	munmap(region->host_addr, region->info.size);
131*6078a454SJean-Philippe Brucker }
132*6078a454SJean-Philippe Brucker 
133*6078a454SJean-Philippe Brucker static int vfio_configure_device(struct kvm *kvm, struct vfio_device *vdev)
134*6078a454SJean-Philippe Brucker {
135*6078a454SJean-Philippe Brucker 	int ret;
136*6078a454SJean-Philippe Brucker 	struct vfio_group *group = vdev->group;
137*6078a454SJean-Philippe Brucker 
138*6078a454SJean-Philippe Brucker 	vdev->fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD,
139*6078a454SJean-Philippe Brucker 			 vdev->params->name);
140*6078a454SJean-Philippe Brucker 	if (vdev->fd < 0) {
141*6078a454SJean-Philippe Brucker 		vfio_dev_warn(vdev, "failed to get fd");
142*6078a454SJean-Philippe Brucker 
143*6078a454SJean-Philippe Brucker 		/* The device might be a bridge without an fd */
144*6078a454SJean-Philippe Brucker 		return 0;
145*6078a454SJean-Philippe Brucker 	}
146*6078a454SJean-Philippe Brucker 
147*6078a454SJean-Philippe Brucker 	vdev->info.argsz = sizeof(vdev->info);
148*6078a454SJean-Philippe Brucker 	if (ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &vdev->info)) {
149*6078a454SJean-Philippe Brucker 		ret = -errno;
150*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to get info");
151*6078a454SJean-Philippe Brucker 		goto err_close_device;
152*6078a454SJean-Philippe Brucker 	}
153*6078a454SJean-Philippe Brucker 
154*6078a454SJean-Philippe Brucker 	if (vdev->info.flags & VFIO_DEVICE_FLAGS_RESET &&
155*6078a454SJean-Philippe Brucker 	    ioctl(vdev->fd, VFIO_DEVICE_RESET) < 0)
156*6078a454SJean-Philippe Brucker 		vfio_dev_warn(vdev, "failed to reset device");
157*6078a454SJean-Philippe Brucker 
158*6078a454SJean-Philippe Brucker 	vdev->regions = calloc(vdev->info.num_regions, sizeof(*vdev->regions));
159*6078a454SJean-Philippe Brucker 	if (!vdev->regions) {
160*6078a454SJean-Philippe Brucker 		ret = -ENOMEM;
161*6078a454SJean-Philippe Brucker 		goto err_close_device;
162*6078a454SJean-Philippe Brucker 	}
163*6078a454SJean-Philippe Brucker 
164*6078a454SJean-Philippe Brucker 	/* Now for the bus-specific initialization... */
165*6078a454SJean-Philippe Brucker 	switch (vdev->params->type) {
166*6078a454SJean-Philippe Brucker 	case VFIO_DEVICE_PCI:
167*6078a454SJean-Philippe Brucker 		BUG_ON(!(vdev->info.flags & VFIO_DEVICE_FLAGS_PCI));
168*6078a454SJean-Philippe Brucker 		ret = vfio_pci_setup_device(kvm, vdev);
169*6078a454SJean-Philippe Brucker 		break;
170*6078a454SJean-Philippe Brucker 	default:
171*6078a454SJean-Philippe Brucker 		BUG_ON(1);
172*6078a454SJean-Philippe Brucker 		ret = -EINVAL;
173*6078a454SJean-Philippe Brucker 	}
174*6078a454SJean-Philippe Brucker 
175*6078a454SJean-Philippe Brucker 	if (ret)
176*6078a454SJean-Philippe Brucker 		goto err_free_regions;
177*6078a454SJean-Philippe Brucker 
178*6078a454SJean-Philippe Brucker 	vfio_dev_info(vdev, "assigned to device number 0x%x in group %lu",
179*6078a454SJean-Philippe Brucker 		      vdev->dev_hdr.dev_num, group->id);
180*6078a454SJean-Philippe Brucker 
181*6078a454SJean-Philippe Brucker 	return 0;
182*6078a454SJean-Philippe Brucker 
183*6078a454SJean-Philippe Brucker err_free_regions:
184*6078a454SJean-Philippe Brucker 	free(vdev->regions);
185*6078a454SJean-Philippe Brucker err_close_device:
186*6078a454SJean-Philippe Brucker 	close(vdev->fd);
187*6078a454SJean-Philippe Brucker 
188*6078a454SJean-Philippe Brucker 	return ret;
189*6078a454SJean-Philippe Brucker }
190*6078a454SJean-Philippe Brucker 
191*6078a454SJean-Philippe Brucker static int vfio_configure_devices(struct kvm *kvm)
192*6078a454SJean-Philippe Brucker {
193*6078a454SJean-Philippe Brucker 	int i, ret;
194*6078a454SJean-Philippe Brucker 
195*6078a454SJean-Philippe Brucker 	for (i = 0; i < kvm->cfg.num_vfio_devices; ++i) {
196*6078a454SJean-Philippe Brucker 		ret = vfio_configure_device(kvm, &vfio_devices[i]);
197*6078a454SJean-Philippe Brucker 		if (ret)
198*6078a454SJean-Philippe Brucker 			return ret;
199*6078a454SJean-Philippe Brucker 	}
200*6078a454SJean-Philippe Brucker 
201*6078a454SJean-Philippe Brucker 	return 0;
202*6078a454SJean-Philippe Brucker }
203*6078a454SJean-Philippe Brucker 
204*6078a454SJean-Philippe Brucker static int vfio_get_iommu_type(void)
205*6078a454SJean-Philippe Brucker {
206*6078a454SJean-Philippe Brucker 	if (ioctl(vfio_container, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU))
207*6078a454SJean-Philippe Brucker 		return VFIO_TYPE1v2_IOMMU;
208*6078a454SJean-Philippe Brucker 
209*6078a454SJean-Philippe Brucker 	if (ioctl(vfio_container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU))
210*6078a454SJean-Philippe Brucker 		return VFIO_TYPE1_IOMMU;
211*6078a454SJean-Philippe Brucker 
212*6078a454SJean-Philippe Brucker 	return -ENODEV;
213*6078a454SJean-Philippe Brucker }
214*6078a454SJean-Philippe Brucker 
215*6078a454SJean-Philippe Brucker static int vfio_map_mem_bank(struct kvm *kvm, struct kvm_mem_bank *bank, void *data)
216*6078a454SJean-Philippe Brucker {
217*6078a454SJean-Philippe Brucker 	int ret = 0;
218*6078a454SJean-Philippe Brucker 	struct vfio_iommu_type1_dma_map dma_map = {
219*6078a454SJean-Philippe Brucker 		.argsz	= sizeof(dma_map),
220*6078a454SJean-Philippe Brucker 		.flags	= VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
221*6078a454SJean-Philippe Brucker 		.vaddr	= (unsigned long)bank->host_addr,
222*6078a454SJean-Philippe Brucker 		.iova	= (u64)bank->guest_phys_addr,
223*6078a454SJean-Philippe Brucker 		.size	= bank->size,
224*6078a454SJean-Philippe Brucker 	};
225*6078a454SJean-Philippe Brucker 
226*6078a454SJean-Philippe Brucker 	/* Map the guest memory for DMA (i.e. provide isolation) */
227*6078a454SJean-Philippe Brucker 	if (ioctl(vfio_container, VFIO_IOMMU_MAP_DMA, &dma_map)) {
228*6078a454SJean-Philippe Brucker 		ret = -errno;
229*6078a454SJean-Philippe Brucker 		pr_err("Failed to map 0x%llx -> 0x%llx (%llu) for DMA",
230*6078a454SJean-Philippe Brucker 		       dma_map.iova, dma_map.vaddr, dma_map.size);
231*6078a454SJean-Philippe Brucker 	}
232*6078a454SJean-Philippe Brucker 
233*6078a454SJean-Philippe Brucker 	return ret;
234*6078a454SJean-Philippe Brucker }
235*6078a454SJean-Philippe Brucker 
236*6078a454SJean-Philippe Brucker static int vfio_unmap_mem_bank(struct kvm *kvm, struct kvm_mem_bank *bank, void *data)
237*6078a454SJean-Philippe Brucker {
238*6078a454SJean-Philippe Brucker 	struct vfio_iommu_type1_dma_unmap dma_unmap = {
239*6078a454SJean-Philippe Brucker 		.argsz = sizeof(dma_unmap),
240*6078a454SJean-Philippe Brucker 		.size = bank->size,
241*6078a454SJean-Philippe Brucker 		.iova = bank->guest_phys_addr,
242*6078a454SJean-Philippe Brucker 	};
243*6078a454SJean-Philippe Brucker 
244*6078a454SJean-Philippe Brucker 	ioctl(vfio_container, VFIO_IOMMU_UNMAP_DMA, &dma_unmap);
245*6078a454SJean-Philippe Brucker 
246*6078a454SJean-Philippe Brucker 	return 0;
247*6078a454SJean-Philippe Brucker }
248*6078a454SJean-Philippe Brucker 
249*6078a454SJean-Philippe Brucker static struct vfio_group *vfio_group_create(struct kvm *kvm, unsigned long id)
250*6078a454SJean-Philippe Brucker {
251*6078a454SJean-Philippe Brucker 	int ret;
252*6078a454SJean-Philippe Brucker 	struct vfio_group *group;
253*6078a454SJean-Philippe Brucker 	char group_node[PATH_MAX];
254*6078a454SJean-Philippe Brucker 	struct vfio_group_status group_status = {
255*6078a454SJean-Philippe Brucker 		.argsz = sizeof(group_status),
256*6078a454SJean-Philippe Brucker 	};
257*6078a454SJean-Philippe Brucker 
258*6078a454SJean-Philippe Brucker 	group = calloc(1, sizeof(*group));
259*6078a454SJean-Philippe Brucker 	if (!group)
260*6078a454SJean-Philippe Brucker 		return NULL;
261*6078a454SJean-Philippe Brucker 
262*6078a454SJean-Philippe Brucker 	group->id	= id;
263*6078a454SJean-Philippe Brucker 	group->refs	= 1;
264*6078a454SJean-Philippe Brucker 
265*6078a454SJean-Philippe Brucker 	ret = snprintf(group_node, PATH_MAX, VFIO_DEV_DIR "/%lu", id);
266*6078a454SJean-Philippe Brucker 	if (ret < 0 || ret == PATH_MAX)
267*6078a454SJean-Philippe Brucker 		return NULL;
268*6078a454SJean-Philippe Brucker 
269*6078a454SJean-Philippe Brucker 	group->fd = open(group_node, O_RDWR);
270*6078a454SJean-Philippe Brucker 	if (group->fd < 0) {
271*6078a454SJean-Philippe Brucker 		pr_err("Failed to open IOMMU group %s", group_node);
272*6078a454SJean-Philippe Brucker 		goto err_free_group;
273*6078a454SJean-Philippe Brucker 	}
274*6078a454SJean-Philippe Brucker 
275*6078a454SJean-Philippe Brucker 	if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &group_status)) {
276*6078a454SJean-Philippe Brucker 		pr_err("Failed to determine status of IOMMU group %lu", id);
277*6078a454SJean-Philippe Brucker 		goto err_close_group;
278*6078a454SJean-Philippe Brucker 	}
279*6078a454SJean-Philippe Brucker 
280*6078a454SJean-Philippe Brucker 	if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
281*6078a454SJean-Philippe Brucker 		pr_err("IOMMU group %lu is not viable", id);
282*6078a454SJean-Philippe Brucker 		goto err_close_group;
283*6078a454SJean-Philippe Brucker 	}
284*6078a454SJean-Philippe Brucker 
285*6078a454SJean-Philippe Brucker 	if (ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &vfio_container)) {
286*6078a454SJean-Philippe Brucker 		pr_err("Failed to add IOMMU group %lu to VFIO container", id);
287*6078a454SJean-Philippe Brucker 		goto err_close_group;
288*6078a454SJean-Philippe Brucker 	}
289*6078a454SJean-Philippe Brucker 
290*6078a454SJean-Philippe Brucker 	list_add(&group->list, &vfio_groups);
291*6078a454SJean-Philippe Brucker 
292*6078a454SJean-Philippe Brucker 	return group;
293*6078a454SJean-Philippe Brucker 
294*6078a454SJean-Philippe Brucker err_close_group:
295*6078a454SJean-Philippe Brucker 	close(group->fd);
296*6078a454SJean-Philippe Brucker err_free_group:
297*6078a454SJean-Philippe Brucker 	free(group);
298*6078a454SJean-Philippe Brucker 
299*6078a454SJean-Philippe Brucker 	return NULL;
300*6078a454SJean-Philippe Brucker }
301*6078a454SJean-Philippe Brucker 
302*6078a454SJean-Philippe Brucker static void vfio_group_exit(struct kvm *kvm, struct vfio_group *group)
303*6078a454SJean-Philippe Brucker {
304*6078a454SJean-Philippe Brucker 	if (--group->refs != 0)
305*6078a454SJean-Philippe Brucker 		return;
306*6078a454SJean-Philippe Brucker 
307*6078a454SJean-Philippe Brucker 	ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER);
308*6078a454SJean-Philippe Brucker 
309*6078a454SJean-Philippe Brucker 	list_del(&group->list);
310*6078a454SJean-Philippe Brucker 	close(group->fd);
311*6078a454SJean-Philippe Brucker 	free(group);
312*6078a454SJean-Philippe Brucker }
313*6078a454SJean-Philippe Brucker 
314*6078a454SJean-Philippe Brucker static struct vfio_group *
315*6078a454SJean-Philippe Brucker vfio_group_get_for_dev(struct kvm *kvm, struct vfio_device *vdev)
316*6078a454SJean-Philippe Brucker {
317*6078a454SJean-Philippe Brucker 	int dirfd;
318*6078a454SJean-Philippe Brucker 	ssize_t ret;
319*6078a454SJean-Philippe Brucker 	char *group_name;
320*6078a454SJean-Philippe Brucker 	unsigned long group_id;
321*6078a454SJean-Philippe Brucker 	char group_path[PATH_MAX];
322*6078a454SJean-Philippe Brucker 	struct vfio_group *group = NULL;
323*6078a454SJean-Philippe Brucker 
324*6078a454SJean-Philippe Brucker 	/* Find IOMMU group for this device */
325*6078a454SJean-Philippe Brucker 	dirfd = open(vdev->sysfs_path, O_DIRECTORY | O_PATH | O_RDONLY);
326*6078a454SJean-Philippe Brucker 	if (dirfd < 0) {
327*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to open '%s'", vdev->sysfs_path);
328*6078a454SJean-Philippe Brucker 		return NULL;
329*6078a454SJean-Philippe Brucker 	}
330*6078a454SJean-Philippe Brucker 
331*6078a454SJean-Philippe Brucker 	ret = readlinkat(dirfd, "iommu_group", group_path, PATH_MAX);
332*6078a454SJean-Philippe Brucker 	if (ret < 0) {
333*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "no iommu_group");
334*6078a454SJean-Philippe Brucker 		goto out_close;
335*6078a454SJean-Philippe Brucker 	}
336*6078a454SJean-Philippe Brucker 	if (ret == PATH_MAX)
337*6078a454SJean-Philippe Brucker 		goto out_close;
338*6078a454SJean-Philippe Brucker 
339*6078a454SJean-Philippe Brucker 	group_path[ret] = '\0';
340*6078a454SJean-Philippe Brucker 
341*6078a454SJean-Philippe Brucker 	group_name = basename(group_path);
342*6078a454SJean-Philippe Brucker 	errno = 0;
343*6078a454SJean-Philippe Brucker 	group_id = strtoul(group_name, NULL, 10);
344*6078a454SJean-Philippe Brucker 	if (errno)
345*6078a454SJean-Philippe Brucker 		goto out_close;
346*6078a454SJean-Philippe Brucker 
347*6078a454SJean-Philippe Brucker 	list_for_each_entry(group, &vfio_groups, list) {
348*6078a454SJean-Philippe Brucker 		if (group->id == group_id) {
349*6078a454SJean-Philippe Brucker 			group->refs++;
350*6078a454SJean-Philippe Brucker 			return group;
351*6078a454SJean-Philippe Brucker 		}
352*6078a454SJean-Philippe Brucker 	}
353*6078a454SJean-Philippe Brucker 
354*6078a454SJean-Philippe Brucker 	group = vfio_group_create(kvm, group_id);
355*6078a454SJean-Philippe Brucker 
356*6078a454SJean-Philippe Brucker out_close:
357*6078a454SJean-Philippe Brucker 	close(dirfd);
358*6078a454SJean-Philippe Brucker 	return group;
359*6078a454SJean-Philippe Brucker }
360*6078a454SJean-Philippe Brucker 
361*6078a454SJean-Philippe Brucker static int vfio_device_init(struct kvm *kvm, struct vfio_device *vdev)
362*6078a454SJean-Philippe Brucker {
363*6078a454SJean-Philippe Brucker 	int ret;
364*6078a454SJean-Philippe Brucker 	char dev_path[PATH_MAX];
365*6078a454SJean-Philippe Brucker 	struct vfio_group *group;
366*6078a454SJean-Philippe Brucker 
367*6078a454SJean-Philippe Brucker 	ret = snprintf(dev_path, PATH_MAX, "/sys/bus/%s/devices/%s",
368*6078a454SJean-Philippe Brucker 		       vdev->params->bus, vdev->params->name);
369*6078a454SJean-Philippe Brucker 	if (ret < 0 || ret == PATH_MAX)
370*6078a454SJean-Philippe Brucker 		return -EINVAL;
371*6078a454SJean-Philippe Brucker 
372*6078a454SJean-Philippe Brucker 	vdev->sysfs_path = strndup(dev_path, PATH_MAX);
373*6078a454SJean-Philippe Brucker 	if (!vdev->sysfs_path)
374*6078a454SJean-Philippe Brucker 		return -errno;
375*6078a454SJean-Philippe Brucker 
376*6078a454SJean-Philippe Brucker 	group = vfio_group_get_for_dev(kvm, vdev);
377*6078a454SJean-Philippe Brucker 	if (!group) {
378*6078a454SJean-Philippe Brucker 		free(vdev->sysfs_path);
379*6078a454SJean-Philippe Brucker 		return -EINVAL;
380*6078a454SJean-Philippe Brucker 	}
381*6078a454SJean-Philippe Brucker 
382*6078a454SJean-Philippe Brucker 	vdev->group = group;
383*6078a454SJean-Philippe Brucker 
384*6078a454SJean-Philippe Brucker 	return 0;
385*6078a454SJean-Philippe Brucker }
386*6078a454SJean-Philippe Brucker 
387*6078a454SJean-Philippe Brucker static void vfio_device_exit(struct kvm *kvm, struct vfio_device *vdev)
388*6078a454SJean-Philippe Brucker {
389*6078a454SJean-Philippe Brucker 	vfio_group_exit(kvm, vdev->group);
390*6078a454SJean-Philippe Brucker 
391*6078a454SJean-Philippe Brucker 	switch (vdev->params->type) {
392*6078a454SJean-Philippe Brucker 	case VFIO_DEVICE_PCI:
393*6078a454SJean-Philippe Brucker 		vfio_pci_teardown_device(kvm, vdev);
394*6078a454SJean-Philippe Brucker 		break;
395*6078a454SJean-Philippe Brucker 	default:
396*6078a454SJean-Philippe Brucker 		vfio_dev_warn(vdev, "no teardown function for device");
397*6078a454SJean-Philippe Brucker 	}
398*6078a454SJean-Philippe Brucker 
399*6078a454SJean-Philippe Brucker 	close(vdev->fd);
400*6078a454SJean-Philippe Brucker 
401*6078a454SJean-Philippe Brucker 	free(vdev->regions);
402*6078a454SJean-Philippe Brucker 	free(vdev->sysfs_path);
403*6078a454SJean-Philippe Brucker }
404*6078a454SJean-Philippe Brucker 
405*6078a454SJean-Philippe Brucker static int vfio_container_init(struct kvm *kvm)
406*6078a454SJean-Philippe Brucker {
407*6078a454SJean-Philippe Brucker 	int api, i, ret, iommu_type;;
408*6078a454SJean-Philippe Brucker 
409*6078a454SJean-Philippe Brucker 	/* Create a container for our IOMMU groups */
410*6078a454SJean-Philippe Brucker 	vfio_container = open(VFIO_DEV_NODE, O_RDWR);
411*6078a454SJean-Philippe Brucker 	if (vfio_container == -1) {
412*6078a454SJean-Philippe Brucker 		ret = errno;
413*6078a454SJean-Philippe Brucker 		pr_err("Failed to open %s", VFIO_DEV_NODE);
414*6078a454SJean-Philippe Brucker 		return ret;
415*6078a454SJean-Philippe Brucker 	}
416*6078a454SJean-Philippe Brucker 
417*6078a454SJean-Philippe Brucker 	api = ioctl(vfio_container, VFIO_GET_API_VERSION);
418*6078a454SJean-Philippe Brucker 	if (api != VFIO_API_VERSION) {
419*6078a454SJean-Philippe Brucker 		pr_err("Unknown VFIO API version %d", api);
420*6078a454SJean-Philippe Brucker 		return -ENODEV;
421*6078a454SJean-Philippe Brucker 	}
422*6078a454SJean-Philippe Brucker 
423*6078a454SJean-Philippe Brucker 	iommu_type = vfio_get_iommu_type();
424*6078a454SJean-Philippe Brucker 	if (iommu_type < 0) {
425*6078a454SJean-Philippe Brucker 		pr_err("VFIO type-1 IOMMU not supported on this platform");
426*6078a454SJean-Philippe Brucker 		return iommu_type;
427*6078a454SJean-Philippe Brucker 	}
428*6078a454SJean-Philippe Brucker 
429*6078a454SJean-Philippe Brucker 	/* Create groups for our devices and add them to the container */
430*6078a454SJean-Philippe Brucker 	for (i = 0; i < kvm->cfg.num_vfio_devices; ++i) {
431*6078a454SJean-Philippe Brucker 		vfio_devices[i].params = &kvm->cfg.vfio_devices[i];
432*6078a454SJean-Philippe Brucker 
433*6078a454SJean-Philippe Brucker 		ret = vfio_device_init(kvm, &vfio_devices[i]);
434*6078a454SJean-Philippe Brucker 		if (ret)
435*6078a454SJean-Philippe Brucker 			return ret;
436*6078a454SJean-Philippe Brucker 	}
437*6078a454SJean-Philippe Brucker 
438*6078a454SJean-Philippe Brucker 	/* Finalise the container */
439*6078a454SJean-Philippe Brucker 	if (ioctl(vfio_container, VFIO_SET_IOMMU, iommu_type)) {
440*6078a454SJean-Philippe Brucker 		ret = -errno;
441*6078a454SJean-Philippe Brucker 		pr_err("Failed to set IOMMU type %d for VFIO container",
442*6078a454SJean-Philippe Brucker 		       iommu_type);
443*6078a454SJean-Philippe Brucker 		return ret;
444*6078a454SJean-Philippe Brucker 	} else {
445*6078a454SJean-Philippe Brucker 		pr_info("Using IOMMU type %d for VFIO container", iommu_type);
446*6078a454SJean-Philippe Brucker 	}
447*6078a454SJean-Philippe Brucker 
448*6078a454SJean-Philippe Brucker 	return kvm__for_each_mem_bank(kvm, KVM_MEM_TYPE_RAM, vfio_map_mem_bank,
449*6078a454SJean-Philippe Brucker 				      NULL);
450*6078a454SJean-Philippe Brucker }
451*6078a454SJean-Philippe Brucker 
452*6078a454SJean-Philippe Brucker static int vfio__init(struct kvm *kvm)
453*6078a454SJean-Philippe Brucker {
454*6078a454SJean-Philippe Brucker 	int ret;
455*6078a454SJean-Philippe Brucker 
456*6078a454SJean-Philippe Brucker 	if (!kvm->cfg.num_vfio_devices)
457*6078a454SJean-Philippe Brucker 		return 0;
458*6078a454SJean-Philippe Brucker 
459*6078a454SJean-Philippe Brucker 	vfio_devices = calloc(kvm->cfg.num_vfio_devices, sizeof(*vfio_devices));
460*6078a454SJean-Philippe Brucker 	if (!vfio_devices)
461*6078a454SJean-Philippe Brucker 		return -ENOMEM;
462*6078a454SJean-Philippe Brucker 
463*6078a454SJean-Philippe Brucker 	ret = vfio_container_init(kvm);
464*6078a454SJean-Philippe Brucker 	if (ret)
465*6078a454SJean-Philippe Brucker 		return ret;
466*6078a454SJean-Philippe Brucker 
467*6078a454SJean-Philippe Brucker 	ret = vfio_configure_devices(kvm);
468*6078a454SJean-Philippe Brucker 	if (ret)
469*6078a454SJean-Philippe Brucker 		return ret;
470*6078a454SJean-Philippe Brucker 
471*6078a454SJean-Philippe Brucker 	return 0;
472*6078a454SJean-Philippe Brucker }
473*6078a454SJean-Philippe Brucker dev_base_init(vfio__init);
474*6078a454SJean-Philippe Brucker 
475*6078a454SJean-Philippe Brucker static int vfio__exit(struct kvm *kvm)
476*6078a454SJean-Philippe Brucker {
477*6078a454SJean-Philippe Brucker 	int i;
478*6078a454SJean-Philippe Brucker 
479*6078a454SJean-Philippe Brucker 	if (!kvm->cfg.num_vfio_devices)
480*6078a454SJean-Philippe Brucker 		return 0;
481*6078a454SJean-Philippe Brucker 
482*6078a454SJean-Philippe Brucker 	for (i = 0; i < kvm->cfg.num_vfio_devices; i++)
483*6078a454SJean-Philippe Brucker 		vfio_device_exit(kvm, &vfio_devices[i]);
484*6078a454SJean-Philippe Brucker 
485*6078a454SJean-Philippe Brucker 	free(vfio_devices);
486*6078a454SJean-Philippe Brucker 
487*6078a454SJean-Philippe Brucker 	kvm__for_each_mem_bank(kvm, KVM_MEM_TYPE_RAM, vfio_unmap_mem_bank, NULL);
488*6078a454SJean-Philippe Brucker 	close(vfio_container);
489*6078a454SJean-Philippe Brucker 
490*6078a454SJean-Philippe Brucker 	free(kvm->cfg.vfio_devices);
491*6078a454SJean-Philippe Brucker 
492*6078a454SJean-Philippe Brucker 	return 0;
493*6078a454SJean-Philippe Brucker }
494*6078a454SJean-Philippe Brucker dev_base_exit(vfio__exit);
495