1/* 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License, version 2, as 4 * published by the Free Software Foundation. 5 * 6 * This program is distributed in the hope that it will be useful, 7 * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 * GNU General Public License for more details. 10 * 11 * You should have received a copy of the GNU General Public License 12 * along with this program; if not, write to the Free Software 13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14 * 15 * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com> 16 * Copyright 2011 David Gibson, IBM Corporation <dwg@au1.ibm.com> 17 */ 18 19#include <linux/types.h> 20#include <linux/string.h> 21#include <linux/kvm.h> 22#include <linux/kvm_host.h> 23#include <linux/highmem.h> 24#include <linux/gfp.h> 25#include <linux/slab.h> 26#include <linux/hugetlb.h> 27#include <linux/list.h> 28#include <linux/anon_inodes.h> 29 30#include <asm/tlbflush.h> 31#include <asm/kvm_ppc.h> 32#include <asm/kvm_book3s.h> 33#include <asm/mmu-hash64.h> 34#include <asm/hvcall.h> 35#include <asm/synch.h> 36#include <asm/ppc-opcode.h> 37#include <asm/kvm_host.h> 38#include <asm/udbg.h> 39 40#define TCES_PER_PAGE (PAGE_SIZE / sizeof(u64)) 41 42static long kvmppc_stt_npages(unsigned long window_size) 43{ 44 return ALIGN((window_size >> SPAPR_TCE_SHIFT) 45 * sizeof(u64), PAGE_SIZE) / PAGE_SIZE; 46} 47 48static void release_spapr_tce_table(struct kvmppc_spapr_tce_table *stt) 49{ 50 struct kvm *kvm = stt->kvm; 51 int i; 52 53 mutex_lock(&kvm->lock); 54 list_del(&stt->list); 55 for (i = 0; i < kvmppc_stt_npages(stt->window_size); i++) 56 __free_page(stt->pages[i]); 57 kfree(stt); 58 mutex_unlock(&kvm->lock); 59 60 kvm_put_kvm(kvm); 61} 62 63static int kvm_spapr_tce_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 64{ 65 struct kvmppc_spapr_tce_table *stt = vma->vm_file->private_data; 66 struct page *page; 67 68 if (vmf->pgoff >= kvmppc_stt_npages(stt->window_size)) 69 return VM_FAULT_SIGBUS; 70 71 page = stt->pages[vmf->pgoff]; 72 get_page(page); 73 vmf->page = page; 74 return 0; 75} 76 77static const struct vm_operations_struct kvm_spapr_tce_vm_ops = { 78 .fault = kvm_spapr_tce_fault, 79}; 80 81static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma) 82{ 83 vma->vm_ops = &kvm_spapr_tce_vm_ops; 84 return 0; 85} 86 87static int kvm_spapr_tce_release(struct inode *inode, struct file *filp) 88{ 89 struct kvmppc_spapr_tce_table *stt = filp->private_data; 90 91 release_spapr_tce_table(stt); 92 return 0; 93} 94 95static const struct file_operations kvm_spapr_tce_fops = { 96 .mmap = kvm_spapr_tce_mmap, 97 .release = kvm_spapr_tce_release, 98}; 99 100long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, 101 struct kvm_create_spapr_tce *args) 102{ 103 struct kvmppc_spapr_tce_table *stt = NULL; 104 long npages; 105 int ret = -ENOMEM; 106 int i; 107 108 /* Check this LIOBN hasn't been previously allocated */ 109 list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) { 110 if (stt->liobn == args->liobn) 111 return -EBUSY; 112 } 113 114 npages = kvmppc_stt_npages(args->window_size); 115 116 stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *), 117 GFP_KERNEL); 118 if (!stt) 119 goto fail; 120 121 stt->liobn = args->liobn; 122 stt->window_size = args->window_size; 123 stt->kvm = kvm; 124 125 for (i = 0; i < npages; i++) { 126 stt->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); 127 if (!stt->pages[i]) 128 goto fail; 129 } 130 131 kvm_get_kvm(kvm); 132 133 mutex_lock(&kvm->lock); 134 list_add(&stt->list, &kvm->arch.spapr_tce_tables); 135 136 mutex_unlock(&kvm->lock); 137 138 return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops, 139 stt, O_RDWR | O_CLOEXEC); 140 141fail: 142 if (stt) { 143 for (i = 0; i < npages; i++) 144 if (stt->pages[i]) 145 __free_page(stt->pages[i]); 146 147 kfree(stt); 148 } 149 return ret; 150} 151