brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 375d628 Raw
192 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * KVM coalesced MMIO4 *5 * Copyright (c) 2008 Bull S.A.S.6 * Copyright 2009 Red Hat, Inc. and/or its affiliates.7 *8 *  Author: Laurent Vivier <Laurent.Vivier@bull.net>9 *10 */11 12#include <kvm/iodev.h>13 14#include <linux/kvm_host.h>15#include <linux/slab.h>16#include <linux/kvm.h>17 18#include "coalesced_mmio.h"19 20static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev)21{22	return container_of(dev, struct kvm_coalesced_mmio_dev, dev);23}24 25static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev,26				   gpa_t addr, int len)27{28	/* is it in a batchable area ?29	 * (addr,len) is fully included in30	 * (zone->addr, zone->size)31	 */32	if (len < 0)33		return 0;34	if (addr + len < addr)35		return 0;36	if (addr < dev->zone.addr)37		return 0;38	if (addr + len > dev->zone.addr + dev->zone.size)39		return 0;40	return 1;41}42 43static int coalesced_mmio_write(struct kvm_vcpu *vcpu,44				struct kvm_io_device *this, gpa_t addr,45				int len, const void *val)46{47	struct kvm_coalesced_mmio_dev *dev = to_mmio(this);48	struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring;49	__u32 insert;50 51	if (!coalesced_mmio_in_range(dev, addr, len))52		return -EOPNOTSUPP;53 54	spin_lock(&dev->kvm->ring_lock);55 56	/*57	 * last is the index of the entry to fill.  Verify userspace hasn't58	 * set last to be out of range, and that there is room in the ring.59	 * Leave one entry free in the ring so that userspace can differentiate60	 * between an empty ring and a full ring.61	 */62	insert = READ_ONCE(ring->last);63	if (insert >= KVM_COALESCED_MMIO_MAX ||64	    (insert + 1) % KVM_COALESCED_MMIO_MAX == READ_ONCE(ring->first)) {65		spin_unlock(&dev->kvm->ring_lock);66		return -EOPNOTSUPP;67	}68 69	/* copy data in first free entry of the ring */70 71	ring->coalesced_mmio[insert].phys_addr = addr;72	ring->coalesced_mmio[insert].len = len;73	memcpy(ring->coalesced_mmio[insert].data, val, len);74	ring->coalesced_mmio[insert].pio = dev->zone.pio;75	smp_wmb();76	ring->last = (insert + 1) % KVM_COALESCED_MMIO_MAX;77	spin_unlock(&dev->kvm->ring_lock);78	return 0;79}80 81static void coalesced_mmio_destructor(struct kvm_io_device *this)82{83	struct kvm_coalesced_mmio_dev *dev = to_mmio(this);84 85	list_del(&dev->list);86 87	kfree(dev);88}89 90static const struct kvm_io_device_ops coalesced_mmio_ops = {91	.write      = coalesced_mmio_write,92	.destructor = coalesced_mmio_destructor,93};94 95int kvm_coalesced_mmio_init(struct kvm *kvm)96{97	struct page *page;98 99	page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);100	if (!page)101		return -ENOMEM;102 103	kvm->coalesced_mmio_ring = page_address(page);104 105	/*106	 * We're using this spinlock to sync access to the coalesced ring.107	 * The list doesn't need its own lock since device registration and108	 * unregistration should only happen when kvm->slots_lock is held.109	 */110	spin_lock_init(&kvm->ring_lock);111	INIT_LIST_HEAD(&kvm->coalesced_zones);112 113	return 0;114}115 116void kvm_coalesced_mmio_free(struct kvm *kvm)117{118	if (kvm->coalesced_mmio_ring)119		free_page((unsigned long)kvm->coalesced_mmio_ring);120}121 122int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,123					 struct kvm_coalesced_mmio_zone *zone)124{125	int ret;126	struct kvm_coalesced_mmio_dev *dev;127 128	if (zone->pio != 1 && zone->pio != 0)129		return -EINVAL;130 131	dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev),132		      GFP_KERNEL_ACCOUNT);133	if (!dev)134		return -ENOMEM;135 136	kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);137	dev->kvm = kvm;138	dev->zone = *zone;139 140	mutex_lock(&kvm->slots_lock);141	ret = kvm_io_bus_register_dev(kvm,142				zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS,143				zone->addr, zone->size, &dev->dev);144	if (ret < 0)145		goto out_free_dev;146	list_add_tail(&dev->list, &kvm->coalesced_zones);147	mutex_unlock(&kvm->slots_lock);148 149	return 0;150 151out_free_dev:152	mutex_unlock(&kvm->slots_lock);153	kfree(dev);154 155	return ret;156}157 158int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,159					   struct kvm_coalesced_mmio_zone *zone)160{161	struct kvm_coalesced_mmio_dev *dev, *tmp;162	int r;163 164	if (zone->pio != 1 && zone->pio != 0)165		return -EINVAL;166 167	mutex_lock(&kvm->slots_lock);168 169	list_for_each_entry_safe(dev, tmp, &kvm->coalesced_zones, list) {170		if (zone->pio == dev->zone.pio &&171		    coalesced_mmio_in_range(dev, zone->addr, zone->size)) {172			r = kvm_io_bus_unregister_dev(kvm,173				zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS, &dev->dev);174			/*175			 * On failure, unregister destroys all devices on the176			 * bus, including the target device. There's no need177			 * to restart the walk as there aren't any zones left.178			 */179			if (r)180				break;181		}182	}183 184	mutex_unlock(&kvm->slots_lock);185 186	/*187	 * Ignore the result of kvm_io_bus_unregister_dev(), from userspace's188	 * perspective, the coalesced MMIO is most definitely unregistered.189	 */190	return 0;191}192