| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Kernel-based Virtual Machine driver for Linux | 
 | 3 |  * | 
 | 4 |  * This module enables machines with Intel VT-x extensions to run virtual | 
 | 5 |  * machines without emulation or binary translation. | 
 | 6 |  * | 
 | 7 |  * Copyright (C) 2006 Qumranet, Inc. | 
 | 8 |  * | 
 | 9 |  * Authors: | 
 | 10 |  *   Avi Kivity   <avi@qumranet.com> | 
 | 11 |  *   Yaniv Kamay  <yaniv@qumranet.com> | 
 | 12 |  * | 
 | 13 |  * This work is licensed under the terms of the GNU GPL, version 2.  See | 
 | 14 |  * the COPYING file in the top-level directory. | 
 | 15 |  * | 
 | 16 |  */ | 
 | 17 |  | 
| Hollis Blanchard | e217402 | 2007-12-03 15:30:24 -0600 | [diff] [blame] | 18 | #include "iodev.h" | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 19 |  | 
| Avi Kivity | edf8841 | 2007-12-16 11:02:48 +0200 | [diff] [blame] | 20 | #include <linux/kvm_host.h> | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 21 | #include <linux/kvm.h> | 
 | 22 | #include <linux/module.h> | 
 | 23 | #include <linux/errno.h> | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 24 | #include <linux/percpu.h> | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 25 | #include <linux/mm.h> | 
 | 26 | #include <linux/miscdevice.h> | 
 | 27 | #include <linux/vmalloc.h> | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 28 | #include <linux/reboot.h> | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 29 | #include <linux/debugfs.h> | 
 | 30 | #include <linux/highmem.h> | 
 | 31 | #include <linux/file.h> | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 32 | #include <linux/sysdev.h> | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 33 | #include <linux/cpu.h> | 
| Alexey Dobriyan | e8edc6e | 2007-05-21 01:22:52 +0400 | [diff] [blame] | 34 | #include <linux/sched.h> | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 35 | #include <linux/cpumask.h> | 
 | 36 | #include <linux/smp.h> | 
| Avi Kivity | d6d2816 | 2007-06-28 08:38:16 -0400 | [diff] [blame] | 37 | #include <linux/anon_inodes.h> | 
| Avi Kivity | 04d2cc7 | 2007-09-10 18:10:54 +0300 | [diff] [blame] | 38 | #include <linux/profile.h> | 
| Anthony Liguori | 7aa81cc | 2007-09-17 14:57:50 -0500 | [diff] [blame] | 39 | #include <linux/kvm_para.h> | 
| Izik Eidus | 6fc138d | 2007-10-09 19:20:39 +0200 | [diff] [blame] | 40 | #include <linux/pagemap.h> | 
| Anthony Liguori | 8d4e128 | 2007-10-18 09:59:34 -0500 | [diff] [blame] | 41 | #include <linux/mman.h> | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 42 | #include <linux/swap.h> | 
| Sheng Yang | e56d532 | 2009-03-12 21:45:39 +0800 | [diff] [blame] | 43 | #include <linux/bitops.h> | 
| Marcelo Tosatti | 547de29 | 2009-05-07 17:55:13 -0300 | [diff] [blame] | 44 | #include <linux/spinlock.h> | 
| Arnd Bergmann | 6ff5894 | 2009-10-22 14:19:27 +0200 | [diff] [blame] | 45 | #include <linux/compat.h> | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 46 | #include <linux/srcu.h> | 
| Joerg Roedel | 8f0b1ab | 2010-01-28 12:37:56 +0100 | [diff] [blame] | 47 | #include <linux/hugetlb.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 48 | #include <linux/slab.h> | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 49 |  | 
| Avi Kivity | e495606 | 2007-06-28 14:15:57 -0400 | [diff] [blame] | 50 | #include <asm/processor.h> | 
| Avi Kivity | e495606 | 2007-06-28 14:15:57 -0400 | [diff] [blame] | 51 | #include <asm/io.h> | 
 | 52 | #include <asm/uaccess.h> | 
| Izik Eidus | 3e021bf | 2007-11-19 11:16:57 +0200 | [diff] [blame] | 53 | #include <asm/pgtable.h> | 
| Alexander Graf | c8240bd | 2009-10-30 05:47:26 +0000 | [diff] [blame] | 54 | #include <asm-generic/bitops/le.h> | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 55 |  | 
| Laurent Vivier | 5f94c17 | 2008-05-30 16:05:54 +0200 | [diff] [blame] | 56 | #include "coalesced_mmio.h" | 
| Laurent Vivier | 5f94c17 | 2008-05-30 16:05:54 +0200 | [diff] [blame] | 57 |  | 
| Marcelo Tosatti | 229456f | 2009-06-17 09:22:14 -0300 | [diff] [blame] | 58 | #define CREATE_TRACE_POINTS | 
 | 59 | #include <trace/events/kvm.h> | 
 | 60 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 61 | MODULE_AUTHOR("Qumranet"); | 
 | 62 | MODULE_LICENSE("GPL"); | 
 | 63 |  | 
| Marcelo Tosatti | fa40a82 | 2009-06-04 15:08:24 -0300 | [diff] [blame] | 64 | /* | 
 | 65 |  * Ordering of locks: | 
 | 66 |  * | 
| Sheng Yang | fae3a35 | 2009-12-15 10:28:07 +0800 | [diff] [blame] | 67 |  * 		kvm->lock --> kvm->slots_lock --> kvm->irq_lock | 
| Marcelo Tosatti | fa40a82 | 2009-06-04 15:08:24 -0300 | [diff] [blame] | 68 |  */ | 
 | 69 |  | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 70 | DEFINE_SPINLOCK(kvm_lock); | 
 | 71 | LIST_HEAD(vm_list); | 
| Avi Kivity | 133de90 | 2007-02-12 00:54:44 -0800 | [diff] [blame] | 72 |  | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 73 | static cpumask_var_t cpus_hardware_enabled; | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 74 | static int kvm_usage_count = 0; | 
 | 75 | static atomic_t hardware_enable_failed; | 
| Avi Kivity | 1b6c016 | 2007-05-24 13:03:52 +0300 | [diff] [blame] | 76 |  | 
| Rusty Russell | c16f862 | 2007-07-30 21:12:19 +1000 | [diff] [blame] | 77 | struct kmem_cache *kvm_vcpu_cache; | 
 | 78 | EXPORT_SYMBOL_GPL(kvm_vcpu_cache); | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 79 |  | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 80 | static __read_mostly struct preempt_ops kvm_preempt_ops; | 
 | 81 |  | 
| Hollis Blanchard | 76f7c87 | 2008-04-15 16:05:42 -0500 | [diff] [blame] | 82 | struct dentry *kvm_debugfs_dir; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 83 |  | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 84 | static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, | 
 | 85 | 			   unsigned long arg); | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 86 | static int hardware_enable_all(void); | 
 | 87 | static void hardware_disable_all(void); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 88 |  | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 89 | static void kvm_io_bus_destroy(struct kvm_io_bus *bus); | 
 | 90 |  | 
| Hannes Eder | e8ba5d3 | 2008-11-28 17:02:42 +0100 | [diff] [blame] | 91 | static bool kvm_rebooting; | 
| Avi Kivity | 4ecac3f | 2008-05-13 13:23:38 +0300 | [diff] [blame] | 92 |  | 
| Marcelo Tosatti | 54dee99 | 2009-06-11 12:07:44 -0300 | [diff] [blame] | 93 | static bool largepages_enabled = true; | 
 | 94 |  | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 95 | inline int kvm_is_mmio_pfn(pfn_t pfn) | 
| Ben-Ami Yassour | cbff90a | 2008-07-28 19:26:24 +0300 | [diff] [blame] | 96 | { | 
| Joerg Roedel | fc5659c | 2009-02-18 14:08:58 +0100 | [diff] [blame] | 97 | 	if (pfn_valid(pfn)) { | 
 | 98 | 		struct page *page = compound_head(pfn_to_page(pfn)); | 
 | 99 | 		return PageReserved(page); | 
 | 100 | 	} | 
| Ben-Ami Yassour | cbff90a | 2008-07-28 19:26:24 +0300 | [diff] [blame] | 101 |  | 
 | 102 | 	return true; | 
 | 103 | } | 
 | 104 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 105 | /* | 
 | 106 |  * Switches to specified vcpu, until a matching vcpu_put() | 
 | 107 |  */ | 
| Carsten Otte | 313a3dc | 2007-10-11 19:16:52 +0200 | [diff] [blame] | 108 | void vcpu_load(struct kvm_vcpu *vcpu) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 109 | { | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 110 | 	int cpu; | 
 | 111 |  | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 112 | 	mutex_lock(&vcpu->mutex); | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 113 | 	cpu = get_cpu(); | 
 | 114 | 	preempt_notifier_register(&vcpu->preempt_notifier); | 
| Carsten Otte | 313a3dc | 2007-10-11 19:16:52 +0200 | [diff] [blame] | 115 | 	kvm_arch_vcpu_load(vcpu, cpu); | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 116 | 	put_cpu(); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 117 | } | 
 | 118 |  | 
| Carsten Otte | 313a3dc | 2007-10-11 19:16:52 +0200 | [diff] [blame] | 119 | void vcpu_put(struct kvm_vcpu *vcpu) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 120 | { | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 121 | 	preempt_disable(); | 
| Carsten Otte | 313a3dc | 2007-10-11 19:16:52 +0200 | [diff] [blame] | 122 | 	kvm_arch_vcpu_put(vcpu); | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 123 | 	preempt_notifier_unregister(&vcpu->preempt_notifier); | 
 | 124 | 	preempt_enable(); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 125 | 	mutex_unlock(&vcpu->mutex); | 
 | 126 | } | 
 | 127 |  | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 128 | static void ack_flush(void *_completed) | 
 | 129 | { | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 130 | } | 
 | 131 |  | 
| Rusty Russell | 4984689 | 2008-12-08 20:26:24 +1030 | [diff] [blame] | 132 | static bool make_all_cpus_request(struct kvm *kvm, unsigned int req) | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 133 | { | 
| Avi Kivity | 597a5f5 | 2008-07-20 14:24:22 +0300 | [diff] [blame] | 134 | 	int i, cpu, me; | 
| Rusty Russell | 6ef7a1b | 2008-12-08 20:28:04 +1030 | [diff] [blame] | 135 | 	cpumask_var_t cpus; | 
 | 136 | 	bool called = true; | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 137 | 	struct kvm_vcpu *vcpu; | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 138 |  | 
| Li Zefan | 79f5599 | 2009-06-15 14:58:26 +0800 | [diff] [blame] | 139 | 	zalloc_cpumask_var(&cpus, GFP_ATOMIC); | 
| Rusty Russell | 6ef7a1b | 2008-12-08 20:28:04 +1030 | [diff] [blame] | 140 |  | 
| Avi Kivity | 70e335e | 2010-02-18 11:25:22 +0200 | [diff] [blame] | 141 | 	raw_spin_lock(&kvm->requests_lock); | 
| Jan Kiszka | e601e3b | 2009-07-20 11:30:12 +0200 | [diff] [blame] | 142 | 	me = smp_processor_id(); | 
| Gleb Natapov | 988a2ca | 2009-06-09 15:56:29 +0300 | [diff] [blame] | 143 | 	kvm_for_each_vcpu(i, vcpu, kvm) { | 
| Rusty Russell | 4984689 | 2008-12-08 20:26:24 +1030 | [diff] [blame] | 144 | 		if (test_and_set_bit(req, &vcpu->requests)) | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 145 | 			continue; | 
 | 146 | 		cpu = vcpu->cpu; | 
| Rusty Russell | 6ef7a1b | 2008-12-08 20:28:04 +1030 | [diff] [blame] | 147 | 		if (cpus != NULL && cpu != -1 && cpu != me) | 
 | 148 | 			cpumask_set_cpu(cpu, cpus); | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 149 | 	} | 
| Rusty Russell | 6ef7a1b | 2008-12-08 20:28:04 +1030 | [diff] [blame] | 150 | 	if (unlikely(cpus == NULL)) | 
 | 151 | 		smp_call_function_many(cpu_online_mask, ack_flush, NULL, 1); | 
 | 152 | 	else if (!cpumask_empty(cpus)) | 
 | 153 | 		smp_call_function_many(cpus, ack_flush, NULL, 1); | 
 | 154 | 	else | 
 | 155 | 		called = false; | 
| Avi Kivity | 70e335e | 2010-02-18 11:25:22 +0200 | [diff] [blame] | 156 | 	raw_spin_unlock(&kvm->requests_lock); | 
| Rusty Russell | 6ef7a1b | 2008-12-08 20:28:04 +1030 | [diff] [blame] | 157 | 	free_cpumask_var(cpus); | 
| Rusty Russell | 4984689 | 2008-12-08 20:26:24 +1030 | [diff] [blame] | 158 | 	return called; | 
 | 159 | } | 
 | 160 |  | 
 | 161 | void kvm_flush_remote_tlbs(struct kvm *kvm) | 
 | 162 | { | 
 | 163 | 	if (make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH)) | 
 | 164 | 		++kvm->stat.remote_tlb_flush; | 
| Avi Kivity | d9e368d | 2007-06-07 19:18:30 +0300 | [diff] [blame] | 165 | } | 
 | 166 |  | 
| Marcelo Tosatti | 2e53d63 | 2008-02-20 14:47:24 -0500 | [diff] [blame] | 167 | void kvm_reload_remote_mmus(struct kvm *kvm) | 
 | 168 | { | 
| Rusty Russell | 4984689 | 2008-12-08 20:26:24 +1030 | [diff] [blame] | 169 | 	make_all_cpus_request(kvm, KVM_REQ_MMU_RELOAD); | 
| Marcelo Tosatti | 2e53d63 | 2008-02-20 14:47:24 -0500 | [diff] [blame] | 170 | } | 
 | 171 |  | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 172 | int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) | 
 | 173 | { | 
 | 174 | 	struct page *page; | 
 | 175 | 	int r; | 
 | 176 |  | 
 | 177 | 	mutex_init(&vcpu->mutex); | 
 | 178 | 	vcpu->cpu = -1; | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 179 | 	vcpu->kvm = kvm; | 
 | 180 | 	vcpu->vcpu_id = id; | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 181 | 	init_waitqueue_head(&vcpu->wq); | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 182 |  | 
 | 183 | 	page = alloc_page(GFP_KERNEL | __GFP_ZERO); | 
 | 184 | 	if (!page) { | 
 | 185 | 		r = -ENOMEM; | 
 | 186 | 		goto fail; | 
 | 187 | 	} | 
 | 188 | 	vcpu->run = page_address(page); | 
 | 189 |  | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 190 | 	r = kvm_arch_vcpu_init(vcpu); | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 191 | 	if (r < 0) | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 192 | 		goto fail_free_run; | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 193 | 	return 0; | 
 | 194 |  | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 195 | fail_free_run: | 
 | 196 | 	free_page((unsigned long)vcpu->run); | 
 | 197 | fail: | 
| Rusty Russell | 76fafa5 | 2007-10-08 10:50:48 +1000 | [diff] [blame] | 198 | 	return r; | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 199 | } | 
 | 200 | EXPORT_SYMBOL_GPL(kvm_vcpu_init); | 
 | 201 |  | 
 | 202 | void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) | 
 | 203 | { | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 204 | 	kvm_arch_vcpu_uninit(vcpu); | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 205 | 	free_page((unsigned long)vcpu->run); | 
 | 206 | } | 
 | 207 | EXPORT_SYMBOL_GPL(kvm_vcpu_uninit); | 
 | 208 |  | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 209 | #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) | 
 | 210 | static inline struct kvm *mmu_notifier_to_kvm(struct mmu_notifier *mn) | 
 | 211 | { | 
 | 212 | 	return container_of(mn, struct kvm, mmu_notifier); | 
 | 213 | } | 
 | 214 |  | 
 | 215 | static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn, | 
 | 216 | 					     struct mm_struct *mm, | 
 | 217 | 					     unsigned long address) | 
 | 218 | { | 
 | 219 | 	struct kvm *kvm = mmu_notifier_to_kvm(mn); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 220 | 	int need_tlb_flush, idx; | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 221 |  | 
 | 222 | 	/* | 
 | 223 | 	 * When ->invalidate_page runs, the linux pte has been zapped | 
 | 224 | 	 * already but the page is still allocated until | 
 | 225 | 	 * ->invalidate_page returns. So if we increase the sequence | 
 | 226 | 	 * here the kvm page fault will notice if the spte can't be | 
 | 227 | 	 * established because the page is going to be freed. If | 
 | 228 | 	 * instead the kvm page fault establishes the spte before | 
 | 229 | 	 * ->invalidate_page runs, kvm_unmap_hva will release it | 
 | 230 | 	 * before returning. | 
 | 231 | 	 * | 
 | 232 | 	 * The sequence increase only need to be seen at spin_unlock | 
 | 233 | 	 * time, and not at spin_lock time. | 
 | 234 | 	 * | 
 | 235 | 	 * Increasing the sequence after the spin_unlock would be | 
 | 236 | 	 * unsafe because the kvm page fault could then establish the | 
 | 237 | 	 * pte after kvm_unmap_hva returned, without noticing the page | 
 | 238 | 	 * is going to be freed. | 
 | 239 | 	 */ | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 240 | 	idx = srcu_read_lock(&kvm->srcu); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 241 | 	spin_lock(&kvm->mmu_lock); | 
 | 242 | 	kvm->mmu_notifier_seq++; | 
 | 243 | 	need_tlb_flush = kvm_unmap_hva(kvm, address); | 
 | 244 | 	spin_unlock(&kvm->mmu_lock); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 245 | 	srcu_read_unlock(&kvm->srcu, idx); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 246 |  | 
 | 247 | 	/* we've to flush the tlb before the pages can be freed */ | 
 | 248 | 	if (need_tlb_flush) | 
 | 249 | 		kvm_flush_remote_tlbs(kvm); | 
 | 250 |  | 
 | 251 | } | 
 | 252 |  | 
| Izik Eidus | 3da0dd4 | 2009-09-23 21:47:18 +0300 | [diff] [blame] | 253 | static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn, | 
 | 254 | 					struct mm_struct *mm, | 
 | 255 | 					unsigned long address, | 
 | 256 | 					pte_t pte) | 
 | 257 | { | 
 | 258 | 	struct kvm *kvm = mmu_notifier_to_kvm(mn); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 259 | 	int idx; | 
| Izik Eidus | 3da0dd4 | 2009-09-23 21:47:18 +0300 | [diff] [blame] | 260 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 261 | 	idx = srcu_read_lock(&kvm->srcu); | 
| Izik Eidus | 3da0dd4 | 2009-09-23 21:47:18 +0300 | [diff] [blame] | 262 | 	spin_lock(&kvm->mmu_lock); | 
 | 263 | 	kvm->mmu_notifier_seq++; | 
 | 264 | 	kvm_set_spte_hva(kvm, address, pte); | 
 | 265 | 	spin_unlock(&kvm->mmu_lock); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 266 | 	srcu_read_unlock(&kvm->srcu, idx); | 
| Izik Eidus | 3da0dd4 | 2009-09-23 21:47:18 +0300 | [diff] [blame] | 267 | } | 
 | 268 |  | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 269 | static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, | 
 | 270 | 						    struct mm_struct *mm, | 
 | 271 | 						    unsigned long start, | 
 | 272 | 						    unsigned long end) | 
 | 273 | { | 
 | 274 | 	struct kvm *kvm = mmu_notifier_to_kvm(mn); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 275 | 	int need_tlb_flush = 0, idx; | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 276 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 277 | 	idx = srcu_read_lock(&kvm->srcu); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 278 | 	spin_lock(&kvm->mmu_lock); | 
 | 279 | 	/* | 
 | 280 | 	 * The count increase must become visible at unlock time as no | 
 | 281 | 	 * spte can be established without taking the mmu_lock and | 
 | 282 | 	 * count is also read inside the mmu_lock critical section. | 
 | 283 | 	 */ | 
 | 284 | 	kvm->mmu_notifier_count++; | 
 | 285 | 	for (; start < end; start += PAGE_SIZE) | 
 | 286 | 		need_tlb_flush |= kvm_unmap_hva(kvm, start); | 
 | 287 | 	spin_unlock(&kvm->mmu_lock); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 288 | 	srcu_read_unlock(&kvm->srcu, idx); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 289 |  | 
 | 290 | 	/* we've to flush the tlb before the pages can be freed */ | 
 | 291 | 	if (need_tlb_flush) | 
 | 292 | 		kvm_flush_remote_tlbs(kvm); | 
 | 293 | } | 
 | 294 |  | 
 | 295 | static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, | 
 | 296 | 						  struct mm_struct *mm, | 
 | 297 | 						  unsigned long start, | 
 | 298 | 						  unsigned long end) | 
 | 299 | { | 
 | 300 | 	struct kvm *kvm = mmu_notifier_to_kvm(mn); | 
 | 301 |  | 
 | 302 | 	spin_lock(&kvm->mmu_lock); | 
 | 303 | 	/* | 
 | 304 | 	 * This sequence increase will notify the kvm page fault that | 
 | 305 | 	 * the page that is going to be mapped in the spte could have | 
 | 306 | 	 * been freed. | 
 | 307 | 	 */ | 
 | 308 | 	kvm->mmu_notifier_seq++; | 
 | 309 | 	/* | 
 | 310 | 	 * The above sequence increase must be visible before the | 
 | 311 | 	 * below count decrease but both values are read by the kvm | 
 | 312 | 	 * page fault under mmu_lock spinlock so we don't need to add | 
 | 313 | 	 * a smb_wmb() here in between the two. | 
 | 314 | 	 */ | 
 | 315 | 	kvm->mmu_notifier_count--; | 
 | 316 | 	spin_unlock(&kvm->mmu_lock); | 
 | 317 |  | 
 | 318 | 	BUG_ON(kvm->mmu_notifier_count < 0); | 
 | 319 | } | 
 | 320 |  | 
 | 321 | static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn, | 
 | 322 | 					      struct mm_struct *mm, | 
 | 323 | 					      unsigned long address) | 
 | 324 | { | 
 | 325 | 	struct kvm *kvm = mmu_notifier_to_kvm(mn); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 326 | 	int young, idx; | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 327 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 328 | 	idx = srcu_read_lock(&kvm->srcu); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 329 | 	spin_lock(&kvm->mmu_lock); | 
 | 330 | 	young = kvm_age_hva(kvm, address); | 
 | 331 | 	spin_unlock(&kvm->mmu_lock); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 332 | 	srcu_read_unlock(&kvm->srcu, idx); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 333 |  | 
 | 334 | 	if (young) | 
 | 335 | 		kvm_flush_remote_tlbs(kvm); | 
 | 336 |  | 
 | 337 | 	return young; | 
 | 338 | } | 
 | 339 |  | 
| Marcelo Tosatti | 85db06e | 2008-12-10 21:23:26 +0100 | [diff] [blame] | 340 | static void kvm_mmu_notifier_release(struct mmu_notifier *mn, | 
 | 341 | 				     struct mm_struct *mm) | 
 | 342 | { | 
 | 343 | 	struct kvm *kvm = mmu_notifier_to_kvm(mn); | 
| Lai Jiangshan | eda2bed | 2010-04-20 14:29:29 +0800 | [diff] [blame] | 344 | 	int idx; | 
 | 345 |  | 
 | 346 | 	idx = srcu_read_lock(&kvm->srcu); | 
| Marcelo Tosatti | 85db06e | 2008-12-10 21:23:26 +0100 | [diff] [blame] | 347 | 	kvm_arch_flush_shadow(kvm); | 
| Lai Jiangshan | eda2bed | 2010-04-20 14:29:29 +0800 | [diff] [blame] | 348 | 	srcu_read_unlock(&kvm->srcu, idx); | 
| Marcelo Tosatti | 85db06e | 2008-12-10 21:23:26 +0100 | [diff] [blame] | 349 | } | 
 | 350 |  | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 351 | static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { | 
 | 352 | 	.invalidate_page	= kvm_mmu_notifier_invalidate_page, | 
 | 353 | 	.invalidate_range_start	= kvm_mmu_notifier_invalidate_range_start, | 
 | 354 | 	.invalidate_range_end	= kvm_mmu_notifier_invalidate_range_end, | 
 | 355 | 	.clear_flush_young	= kvm_mmu_notifier_clear_flush_young, | 
| Izik Eidus | 3da0dd4 | 2009-09-23 21:47:18 +0300 | [diff] [blame] | 356 | 	.change_pte		= kvm_mmu_notifier_change_pte, | 
| Marcelo Tosatti | 85db06e | 2008-12-10 21:23:26 +0100 | [diff] [blame] | 357 | 	.release		= kvm_mmu_notifier_release, | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 358 | }; | 
| Avi Kivity | 4c07b0a | 2009-12-20 14:54:04 +0200 | [diff] [blame] | 359 |  | 
 | 360 | static int kvm_init_mmu_notifier(struct kvm *kvm) | 
 | 361 | { | 
 | 362 | 	kvm->mmu_notifier.ops = &kvm_mmu_notifier_ops; | 
 | 363 | 	return mmu_notifier_register(&kvm->mmu_notifier, current->mm); | 
 | 364 | } | 
 | 365 |  | 
 | 366 | #else  /* !(CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER) */ | 
 | 367 |  | 
 | 368 | static int kvm_init_mmu_notifier(struct kvm *kvm) | 
 | 369 | { | 
 | 370 | 	return 0; | 
 | 371 | } | 
 | 372 |  | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 373 | #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */ | 
 | 374 |  | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 375 | static struct kvm *kvm_create_vm(void) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 376 | { | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 377 | 	int r = 0, i; | 
| Zhang Xiantao | d19a9cd | 2007-11-18 18:43:45 +0800 | [diff] [blame] | 378 | 	struct kvm *kvm = kvm_arch_create_vm(); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 379 |  | 
| Zhang Xiantao | d19a9cd | 2007-11-18 18:43:45 +0800 | [diff] [blame] | 380 | 	if (IS_ERR(kvm)) | 
 | 381 | 		goto out; | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 382 |  | 
 | 383 | 	r = hardware_enable_all(); | 
 | 384 | 	if (r) | 
 | 385 | 		goto out_err_nodisable; | 
 | 386 |  | 
| Avi Kivity | 75858a8 | 2009-01-04 17:10:50 +0200 | [diff] [blame] | 387 | #ifdef CONFIG_HAVE_KVM_IRQCHIP | 
 | 388 | 	INIT_HLIST_HEAD(&kvm->mask_notifier_list); | 
| Gleb Natapov | 136bdfe | 2009-08-24 11:54:23 +0300 | [diff] [blame] | 389 | 	INIT_HLIST_HEAD(&kvm->irq_ack_notifier_list); | 
| Avi Kivity | 75858a8 | 2009-01-04 17:10:50 +0200 | [diff] [blame] | 390 | #endif | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 391 |  | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 392 | 	r = -ENOMEM; | 
 | 393 | 	kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL); | 
 | 394 | 	if (!kvm->memslots) | 
 | 395 | 		goto out_err; | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 396 | 	if (init_srcu_struct(&kvm->srcu)) | 
 | 397 | 		goto out_err; | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 398 | 	for (i = 0; i < KVM_NR_BUSES; i++) { | 
 | 399 | 		kvm->buses[i] = kzalloc(sizeof(struct kvm_io_bus), | 
 | 400 | 					GFP_KERNEL); | 
 | 401 | 		if (!kvm->buses[i]) { | 
 | 402 | 			cleanup_srcu_struct(&kvm->srcu); | 
 | 403 | 			goto out_err; | 
 | 404 | 		} | 
 | 405 | 	} | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 406 |  | 
| Avi Kivity | 4c07b0a | 2009-12-20 14:54:04 +0200 | [diff] [blame] | 407 | 	r = kvm_init_mmu_notifier(kvm); | 
| Avi Kivity | 283d0c6 | 2009-12-20 14:25:19 +0200 | [diff] [blame] | 408 | 	if (r) { | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 409 | 		cleanup_srcu_struct(&kvm->srcu); | 
| Avi Kivity | 283d0c6 | 2009-12-20 14:25:19 +0200 | [diff] [blame] | 410 | 		goto out_err; | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 411 | 	} | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 412 |  | 
| Avi Kivity | 6d4e4c4 | 2007-11-21 16:41:05 +0200 | [diff] [blame] | 413 | 	kvm->mm = current->mm; | 
 | 414 | 	atomic_inc(&kvm->mm->mm_count); | 
| Marcelo Tosatti | aaee2c9 | 2007-12-20 19:18:26 -0500 | [diff] [blame] | 415 | 	spin_lock_init(&kvm->mmu_lock); | 
| Avi Kivity | 70e335e | 2010-02-18 11:25:22 +0200 | [diff] [blame] | 416 | 	raw_spin_lock_init(&kvm->requests_lock); | 
| Gregory Haskins | d34e6b1 | 2009-07-07 17:08:49 -0400 | [diff] [blame] | 417 | 	kvm_eventfd_init(kvm); | 
| Shaohua Li | 11ec280 | 2007-07-23 14:51:37 +0800 | [diff] [blame] | 418 | 	mutex_init(&kvm->lock); | 
| Marcelo Tosatti | 60eead7 | 2009-06-04 15:08:23 -0300 | [diff] [blame] | 419 | 	mutex_init(&kvm->irq_lock); | 
| Marcelo Tosatti | 79fac95 | 2009-12-23 14:35:26 -0200 | [diff] [blame] | 420 | 	mutex_init(&kvm->slots_lock); | 
| Izik Eidus | d39f13b | 2008-03-30 16:01:25 +0300 | [diff] [blame] | 421 | 	atomic_set(&kvm->users_count, 1); | 
| Rusty Russell | 5e58cfe | 2007-07-23 17:08:21 +1000 | [diff] [blame] | 422 | 	spin_lock(&kvm_lock); | 
 | 423 | 	list_add(&kvm->vm_list, &vm_list); | 
 | 424 | 	spin_unlock(&kvm_lock); | 
| Laurent Vivier | 5f94c17 | 2008-05-30 16:05:54 +0200 | [diff] [blame] | 425 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | 
 | 426 | 	kvm_coalesced_mmio_init(kvm); | 
 | 427 | #endif | 
| Zhang Xiantao | d19a9cd | 2007-11-18 18:43:45 +0800 | [diff] [blame] | 428 | out: | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 429 | 	return kvm; | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 430 |  | 
 | 431 | out_err: | 
 | 432 | 	hardware_disable_all(); | 
 | 433 | out_err_nodisable: | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 434 | 	for (i = 0; i < KVM_NR_BUSES; i++) | 
 | 435 | 		kfree(kvm->buses[i]); | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 436 | 	kfree(kvm->memslots); | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 437 | 	kfree(kvm); | 
 | 438 | 	return ERR_PTR(r); | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 439 | } | 
 | 440 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 441 | /* | 
 | 442 |  * Free any memory in @free but not in @dont. | 
 | 443 |  */ | 
 | 444 | static void kvm_free_physmem_slot(struct kvm_memory_slot *free, | 
 | 445 | 				  struct kvm_memory_slot *dont) | 
 | 446 | { | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 447 | 	int i; | 
 | 448 |  | 
| Izik Eidus | 290fc38 | 2007-09-27 14:11:22 +0200 | [diff] [blame] | 449 | 	if (!dont || free->rmap != dont->rmap) | 
 | 450 | 		vfree(free->rmap); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 451 |  | 
 | 452 | 	if (!dont || free->dirty_bitmap != dont->dirty_bitmap) | 
 | 453 | 		vfree(free->dirty_bitmap); | 
 | 454 |  | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 455 |  | 
 | 456 | 	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { | 
 | 457 | 		if (!dont || free->lpage_info[i] != dont->lpage_info[i]) { | 
 | 458 | 			vfree(free->lpage_info[i]); | 
 | 459 | 			free->lpage_info[i] = NULL; | 
 | 460 | 		} | 
 | 461 | 	} | 
| Marcelo Tosatti | 05da455 | 2008-02-23 11:44:30 -0300 | [diff] [blame] | 462 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 463 | 	free->npages = 0; | 
| Al Viro | 8b6d44c | 2007-02-09 16:38:40 +0000 | [diff] [blame] | 464 | 	free->dirty_bitmap = NULL; | 
| Anthony Liguori | 8d4e128 | 2007-10-18 09:59:34 -0500 | [diff] [blame] | 465 | 	free->rmap = NULL; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 466 | } | 
 | 467 |  | 
| Zhang Xiantao | d19a9cd | 2007-11-18 18:43:45 +0800 | [diff] [blame] | 468 | void kvm_free_physmem(struct kvm *kvm) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 469 | { | 
 | 470 | 	int i; | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 471 | 	struct kvm_memslots *slots = kvm->memslots; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 472 |  | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 473 | 	for (i = 0; i < slots->nmemslots; ++i) | 
 | 474 | 		kvm_free_physmem_slot(&slots->memslots[i], NULL); | 
 | 475 |  | 
 | 476 | 	kfree(kvm->memslots); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 477 | } | 
 | 478 |  | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 479 | static void kvm_destroy_vm(struct kvm *kvm) | 
 | 480 | { | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 481 | 	int i; | 
| Avi Kivity | 6d4e4c4 | 2007-11-21 16:41:05 +0200 | [diff] [blame] | 482 | 	struct mm_struct *mm = kvm->mm; | 
 | 483 |  | 
| Sheng Yang | ad8ba2c | 2009-01-06 10:03:02 +0800 | [diff] [blame] | 484 | 	kvm_arch_sync_events(kvm); | 
| Avi Kivity | 133de90 | 2007-02-12 00:54:44 -0800 | [diff] [blame] | 485 | 	spin_lock(&kvm_lock); | 
 | 486 | 	list_del(&kvm->vm_list); | 
 | 487 | 	spin_unlock(&kvm_lock); | 
| Avi Kivity | 399ec80 | 2008-11-19 13:58:46 +0200 | [diff] [blame] | 488 | 	kvm_free_irq_routing(kvm); | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 489 | 	for (i = 0; i < KVM_NR_BUSES; i++) | 
 | 490 | 		kvm_io_bus_destroy(kvm->buses[i]); | 
| Avi Kivity | 980da6c | 2009-12-20 15:13:43 +0200 | [diff] [blame] | 491 | 	kvm_coalesced_mmio_free(kvm); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 492 | #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) | 
 | 493 | 	mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm); | 
| Gleb Natapov | f00be0c | 2009-03-19 12:20:36 +0200 | [diff] [blame] | 494 | #else | 
 | 495 | 	kvm_arch_flush_shadow(kvm); | 
| Andrea Arcangeli | e930bff | 2008-07-25 16:24:52 +0200 | [diff] [blame] | 496 | #endif | 
| Zhang Xiantao | d19a9cd | 2007-11-18 18:43:45 +0800 | [diff] [blame] | 497 | 	kvm_arch_destroy_vm(kvm); | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 498 | 	hardware_disable_all(); | 
| Avi Kivity | 6d4e4c4 | 2007-11-21 16:41:05 +0200 | [diff] [blame] | 499 | 	mmdrop(mm); | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 500 | } | 
 | 501 |  | 
| Izik Eidus | d39f13b | 2008-03-30 16:01:25 +0300 | [diff] [blame] | 502 | void kvm_get_kvm(struct kvm *kvm) | 
 | 503 | { | 
 | 504 | 	atomic_inc(&kvm->users_count); | 
 | 505 | } | 
 | 506 | EXPORT_SYMBOL_GPL(kvm_get_kvm); | 
 | 507 |  | 
 | 508 | void kvm_put_kvm(struct kvm *kvm) | 
 | 509 | { | 
 | 510 | 	if (atomic_dec_and_test(&kvm->users_count)) | 
 | 511 | 		kvm_destroy_vm(kvm); | 
 | 512 | } | 
 | 513 | EXPORT_SYMBOL_GPL(kvm_put_kvm); | 
 | 514 |  | 
 | 515 |  | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 516 | static int kvm_vm_release(struct inode *inode, struct file *filp) | 
 | 517 | { | 
 | 518 | 	struct kvm *kvm = filp->private_data; | 
 | 519 |  | 
| Gregory Haskins | 721eecb | 2009-05-20 10:30:49 -0400 | [diff] [blame] | 520 | 	kvm_irqfd_release(kvm); | 
 | 521 |  | 
| Izik Eidus | d39f13b | 2008-03-30 16:01:25 +0300 | [diff] [blame] | 522 | 	kvm_put_kvm(kvm); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 523 | 	return 0; | 
 | 524 | } | 
 | 525 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 526 | /* | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 527 |  * Allocate some memory and give it an address in the guest physical address | 
 | 528 |  * space. | 
 | 529 |  * | 
 | 530 |  * Discontiguous memory is allowed, mostly for framebuffers. | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 531 |  * | 
| Marcelo Tosatti | 10589a4 | 2007-12-20 19:18:22 -0500 | [diff] [blame] | 532 |  * Must be called holding mmap_sem for write. | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 533 |  */ | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 534 | int __kvm_set_memory_region(struct kvm *kvm, | 
 | 535 | 			    struct kvm_userspace_memory_region *mem, | 
 | 536 | 			    int user_alloc) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 537 | { | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 538 | 	int r, flush_shadow = 0; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 539 | 	gfn_t base_gfn; | 
| Heiko Carstens | 28bcb11 | 2009-09-03 17:35:35 +0200 | [diff] [blame] | 540 | 	unsigned long npages; | 
 | 541 | 	unsigned long i; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 542 | 	struct kvm_memory_slot *memslot; | 
 | 543 | 	struct kvm_memory_slot old, new; | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 544 | 	struct kvm_memslots *slots, *old_memslots; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 545 |  | 
 | 546 | 	r = -EINVAL; | 
 | 547 | 	/* General sanity checks */ | 
 | 548 | 	if (mem->memory_size & (PAGE_SIZE - 1)) | 
 | 549 | 		goto out; | 
 | 550 | 	if (mem->guest_phys_addr & (PAGE_SIZE - 1)) | 
 | 551 | 		goto out; | 
| Sheng Yang | e7cacd4 | 2008-11-11 15:30:40 +0800 | [diff] [blame] | 552 | 	if (user_alloc && (mem->userspace_addr & (PAGE_SIZE - 1))) | 
| Hollis Blanchard | 7874980 | 2008-11-07 13:32:12 -0600 | [diff] [blame] | 553 | 		goto out; | 
| Izik Eidus | e0d62c7 | 2007-10-24 23:57:46 +0200 | [diff] [blame] | 554 | 	if (mem->slot >= KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 555 | 		goto out; | 
 | 556 | 	if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) | 
 | 557 | 		goto out; | 
 | 558 |  | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 559 | 	memslot = &kvm->memslots->memslots[mem->slot]; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 560 | 	base_gfn = mem->guest_phys_addr >> PAGE_SHIFT; | 
 | 561 | 	npages = mem->memory_size >> PAGE_SHIFT; | 
 | 562 |  | 
 | 563 | 	if (!npages) | 
 | 564 | 		mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES; | 
 | 565 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 566 | 	new = old = *memslot; | 
 | 567 |  | 
 | 568 | 	new.base_gfn = base_gfn; | 
 | 569 | 	new.npages = npages; | 
 | 570 | 	new.flags = mem->flags; | 
 | 571 |  | 
 | 572 | 	/* Disallow changing a memory slot's size. */ | 
 | 573 | 	r = -EINVAL; | 
 | 574 | 	if (npages && old.npages && npages != old.npages) | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 575 | 		goto out_free; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 576 |  | 
 | 577 | 	/* Check for overlaps */ | 
 | 578 | 	r = -EEXIST; | 
 | 579 | 	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 580 | 		struct kvm_memory_slot *s = &kvm->memslots->memslots[i]; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 581 |  | 
| Jan Kiszka | 4cd481f | 2009-04-13 11:59:32 +0200 | [diff] [blame] | 582 | 		if (s == memslot || !s->npages) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 583 | 			continue; | 
 | 584 | 		if (!((base_gfn + npages <= s->base_gfn) || | 
 | 585 | 		      (base_gfn >= s->base_gfn + s->npages))) | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 586 | 			goto out_free; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 587 | 	} | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 588 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 589 | 	/* Free page dirty bitmap if unneeded */ | 
 | 590 | 	if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES)) | 
| Al Viro | 8b6d44c | 2007-02-09 16:38:40 +0000 | [diff] [blame] | 591 | 		new.dirty_bitmap = NULL; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 592 |  | 
 | 593 | 	r = -ENOMEM; | 
 | 594 |  | 
 | 595 | 	/* Allocate if a slot is being created */ | 
| Carsten Otte | eff0114 | 2008-06-27 15:05:31 +0200 | [diff] [blame] | 596 | #ifndef CONFIG_S390 | 
| Anthony Liguori | 8d4e128 | 2007-10-18 09:59:34 -0500 | [diff] [blame] | 597 | 	if (npages && !new.rmap) { | 
| Mike Day | d77c26f | 2007-10-08 09:02:08 -0400 | [diff] [blame] | 598 | 		new.rmap = vmalloc(npages * sizeof(struct page *)); | 
| Izik Eidus | 290fc38 | 2007-09-27 14:11:22 +0200 | [diff] [blame] | 599 |  | 
 | 600 | 		if (!new.rmap) | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 601 | 			goto out_free; | 
| Izik Eidus | 290fc38 | 2007-09-27 14:11:22 +0200 | [diff] [blame] | 602 |  | 
| Izik Eidus | 290fc38 | 2007-09-27 14:11:22 +0200 | [diff] [blame] | 603 | 		memset(new.rmap, 0, npages * sizeof(*new.rmap)); | 
| Anthony Liguori | 8d4e128 | 2007-10-18 09:59:34 -0500 | [diff] [blame] | 604 |  | 
| Izik Eidus | 80b14b5 | 2007-10-25 11:54:04 +0200 | [diff] [blame] | 605 | 		new.user_alloc = user_alloc; | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 606 | 		new.userspace_addr = mem->userspace_addr; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 607 | 	} | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 608 | 	if (!npages) | 
 | 609 | 		goto skip_lpage; | 
| Marcelo Tosatti | 05da455 | 2008-02-23 11:44:30 -0300 | [diff] [blame] | 610 |  | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 611 | 	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { | 
| Heiko Carstens | 28bcb11 | 2009-09-03 17:35:35 +0200 | [diff] [blame] | 612 | 		unsigned long ugfn; | 
 | 613 | 		unsigned long j; | 
 | 614 | 		int lpages; | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 615 | 		int level = i + 2; | 
| Marcelo Tosatti | 05da455 | 2008-02-23 11:44:30 -0300 | [diff] [blame] | 616 |  | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 617 | 		/* Avoid unused variable warning if no large pages */ | 
 | 618 | 		(void)level; | 
 | 619 |  | 
 | 620 | 		if (new.lpage_info[i]) | 
 | 621 | 			continue; | 
 | 622 |  | 
 | 623 | 		lpages = 1 + (base_gfn + npages - 1) / | 
 | 624 | 			     KVM_PAGES_PER_HPAGE(level); | 
 | 625 | 		lpages -= base_gfn / KVM_PAGES_PER_HPAGE(level); | 
 | 626 |  | 
 | 627 | 		new.lpage_info[i] = vmalloc(lpages * sizeof(*new.lpage_info[i])); | 
 | 628 |  | 
 | 629 | 		if (!new.lpage_info[i]) | 
| Marcelo Tosatti | 05da455 | 2008-02-23 11:44:30 -0300 | [diff] [blame] | 630 | 			goto out_free; | 
 | 631 |  | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 632 | 		memset(new.lpage_info[i], 0, | 
 | 633 | 		       lpages * sizeof(*new.lpage_info[i])); | 
| Marcelo Tosatti | 05da455 | 2008-02-23 11:44:30 -0300 | [diff] [blame] | 634 |  | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 635 | 		if (base_gfn % KVM_PAGES_PER_HPAGE(level)) | 
 | 636 | 			new.lpage_info[i][0].write_count = 1; | 
 | 637 | 		if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE(level)) | 
 | 638 | 			new.lpage_info[i][lpages - 1].write_count = 1; | 
| Avi Kivity | ac04527 | 2009-06-08 15:52:39 +0300 | [diff] [blame] | 639 | 		ugfn = new.userspace_addr >> PAGE_SHIFT; | 
 | 640 | 		/* | 
 | 641 | 		 * If the gfn and userspace address are not aligned wrt each | 
| Marcelo Tosatti | 54dee99 | 2009-06-11 12:07:44 -0300 | [diff] [blame] | 642 | 		 * other, or if explicitly asked to, disable large page | 
 | 643 | 		 * support for this slot | 
| Avi Kivity | ac04527 | 2009-06-08 15:52:39 +0300 | [diff] [blame] | 644 | 		 */ | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 645 | 		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) || | 
| Marcelo Tosatti | 54dee99 | 2009-06-11 12:07:44 -0300 | [diff] [blame] | 646 | 		    !largepages_enabled) | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 647 | 			for (j = 0; j < lpages; ++j) | 
 | 648 | 				new.lpage_info[i][j].write_count = 1; | 
| Marcelo Tosatti | 05da455 | 2008-02-23 11:44:30 -0300 | [diff] [blame] | 649 | 	} | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 650 |  | 
| Joerg Roedel | ec04b26 | 2009-06-19 15:16:23 +0200 | [diff] [blame] | 651 | skip_lpage: | 
 | 652 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 653 | 	/* Allocate page dirty bitmap if needed */ | 
 | 654 | 	if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) { | 
| Takuya Yoshikawa | 87bf6e7 | 2010-04-12 19:35:35 +0900 | [diff] [blame] | 655 | 		unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(&new); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 656 |  | 
 | 657 | 		new.dirty_bitmap = vmalloc(dirty_bytes); | 
 | 658 | 		if (!new.dirty_bitmap) | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 659 | 			goto out_free; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 660 | 		memset(new.dirty_bitmap, 0, dirty_bytes); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 661 | 		/* destroy any largepage mappings for dirty tracking */ | 
| Izik Eidus | e244584 | 2009-06-10 19:23:24 +0300 | [diff] [blame] | 662 | 		if (old.npages) | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 663 | 			flush_shadow = 1; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 664 | 	} | 
| Christian Borntraeger | 3eea843 | 2009-06-23 17:24:06 +0200 | [diff] [blame] | 665 | #else  /* not defined CONFIG_S390 */ | 
 | 666 | 	new.user_alloc = user_alloc; | 
 | 667 | 	if (user_alloc) | 
 | 668 | 		new.userspace_addr = mem->userspace_addr; | 
| Carsten Otte | eff0114 | 2008-06-27 15:05:31 +0200 | [diff] [blame] | 669 | #endif /* not defined CONFIG_S390 */ | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 670 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 671 | 	if (!npages) { | 
 | 672 | 		r = -ENOMEM; | 
 | 673 | 		slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL); | 
 | 674 | 		if (!slots) | 
 | 675 | 			goto out_free; | 
 | 676 | 		memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots)); | 
 | 677 | 		if (mem->slot >= slots->nmemslots) | 
 | 678 | 			slots->nmemslots = mem->slot + 1; | 
 | 679 | 		slots->memslots[mem->slot].flags |= KVM_MEMSLOT_INVALID; | 
 | 680 |  | 
 | 681 | 		old_memslots = kvm->memslots; | 
 | 682 | 		rcu_assign_pointer(kvm->memslots, slots); | 
 | 683 | 		synchronize_srcu_expedited(&kvm->srcu); | 
 | 684 | 		/* From this point no new shadow pages pointing to a deleted | 
 | 685 | 		 * memslot will be created. | 
 | 686 | 		 * | 
 | 687 | 		 * validation of sp->gfn happens in: | 
 | 688 | 		 * 	- gfn_to_hva (kvm_read_guest, gfn_to_pfn) | 
 | 689 | 		 * 	- kvm_is_visible_gfn (mmu_check_roots) | 
 | 690 | 		 */ | 
| Marcelo Tosatti | 34d4cb8 | 2008-07-10 20:49:31 -0300 | [diff] [blame] | 691 | 		kvm_arch_flush_shadow(kvm); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 692 | 		kfree(old_memslots); | 
 | 693 | 	} | 
| Marcelo Tosatti | 34d4cb8 | 2008-07-10 20:49:31 -0300 | [diff] [blame] | 694 |  | 
| Marcelo Tosatti | f7784b8 | 2009-12-23 14:35:18 -0200 | [diff] [blame] | 695 | 	r = kvm_arch_prepare_memory_region(kvm, &new, old, mem, user_alloc); | 
 | 696 | 	if (r) | 
 | 697 | 		goto out_free; | 
 | 698 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 699 | #ifdef CONFIG_DMAR | 
 | 700 | 	/* map the pages in iommu page table */ | 
 | 701 | 	if (npages) { | 
 | 702 | 		r = kvm_iommu_map_pages(kvm, &new); | 
 | 703 | 		if (r) | 
 | 704 | 			goto out_free; | 
 | 705 | 	} | 
 | 706 | #endif | 
| Andrea Arcangeli | 604b38a | 2008-07-25 16:32:03 +0200 | [diff] [blame] | 707 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 708 | 	r = -ENOMEM; | 
 | 709 | 	slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL); | 
 | 710 | 	if (!slots) | 
 | 711 | 		goto out_free; | 
 | 712 | 	memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots)); | 
 | 713 | 	if (mem->slot >= slots->nmemslots) | 
 | 714 | 		slots->nmemslots = mem->slot + 1; | 
 | 715 |  | 
 | 716 | 	/* actual memory is freed via old in kvm_free_physmem_slot below */ | 
 | 717 | 	if (!npages) { | 
 | 718 | 		new.rmap = NULL; | 
 | 719 | 		new.dirty_bitmap = NULL; | 
 | 720 | 		for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) | 
 | 721 | 			new.lpage_info[i] = NULL; | 
 | 722 | 	} | 
 | 723 |  | 
 | 724 | 	slots->memslots[mem->slot] = new; | 
 | 725 | 	old_memslots = kvm->memslots; | 
 | 726 | 	rcu_assign_pointer(kvm->memslots, slots); | 
 | 727 | 	synchronize_srcu_expedited(&kvm->srcu); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 728 |  | 
| Marcelo Tosatti | f7784b8 | 2009-12-23 14:35:18 -0200 | [diff] [blame] | 729 | 	kvm_arch_commit_memory_region(kvm, mem, old, user_alloc); | 
| Zhang Xiantao | 3ad82a7 | 2007-11-20 13:11:38 +0800 | [diff] [blame] | 730 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 731 | 	kvm_free_physmem_slot(&old, &new); | 
 | 732 | 	kfree(old_memslots); | 
 | 733 |  | 
 | 734 | 	if (flush_shadow) | 
 | 735 | 		kvm_arch_flush_shadow(kvm); | 
 | 736 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 737 | 	return 0; | 
 | 738 |  | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 739 | out_free: | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 740 | 	kvm_free_physmem_slot(&new, &old); | 
 | 741 | out: | 
 | 742 | 	return r; | 
| Izik Eidus | 210c7c4 | 2007-10-24 23:52:57 +0200 | [diff] [blame] | 743 |  | 
 | 744 | } | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 745 | EXPORT_SYMBOL_GPL(__kvm_set_memory_region); | 
 | 746 |  | 
 | 747 | int kvm_set_memory_region(struct kvm *kvm, | 
 | 748 | 			  struct kvm_userspace_memory_region *mem, | 
 | 749 | 			  int user_alloc) | 
 | 750 | { | 
 | 751 | 	int r; | 
 | 752 |  | 
| Marcelo Tosatti | 79fac95 | 2009-12-23 14:35:26 -0200 | [diff] [blame] | 753 | 	mutex_lock(&kvm->slots_lock); | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 754 | 	r = __kvm_set_memory_region(kvm, mem, user_alloc); | 
| Marcelo Tosatti | 79fac95 | 2009-12-23 14:35:26 -0200 | [diff] [blame] | 755 | 	mutex_unlock(&kvm->slots_lock); | 
| Sheng Yang | f78e0e2 | 2007-10-29 09:40:42 +0800 | [diff] [blame] | 756 | 	return r; | 
 | 757 | } | 
| Izik Eidus | 210c7c4 | 2007-10-24 23:52:57 +0200 | [diff] [blame] | 758 | EXPORT_SYMBOL_GPL(kvm_set_memory_region); | 
 | 759 |  | 
| Carsten Otte | 1fe779f | 2007-10-29 16:08:35 +0100 | [diff] [blame] | 760 | int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, | 
 | 761 | 				   struct | 
 | 762 | 				   kvm_userspace_memory_region *mem, | 
 | 763 | 				   int user_alloc) | 
| Izik Eidus | 210c7c4 | 2007-10-24 23:52:57 +0200 | [diff] [blame] | 764 | { | 
| Izik Eidus | e0d62c7 | 2007-10-24 23:57:46 +0200 | [diff] [blame] | 765 | 	if (mem->slot >= KVM_MEMORY_SLOTS) | 
 | 766 | 		return -EINVAL; | 
| Izik Eidus | 210c7c4 | 2007-10-24 23:52:57 +0200 | [diff] [blame] | 767 | 	return kvm_set_memory_region(kvm, mem, user_alloc); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 768 | } | 
 | 769 |  | 
| Zhang Xiantao | 5bb064d | 2007-11-18 20:29:43 +0800 | [diff] [blame] | 770 | int kvm_get_dirty_log(struct kvm *kvm, | 
 | 771 | 			struct kvm_dirty_log *log, int *is_dirty) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 772 | { | 
 | 773 | 	struct kvm_memory_slot *memslot; | 
 | 774 | 	int r, i; | 
| Takuya Yoshikawa | 87bf6e7 | 2010-04-12 19:35:35 +0900 | [diff] [blame] | 775 | 	unsigned long n; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 776 | 	unsigned long any = 0; | 
 | 777 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 778 | 	r = -EINVAL; | 
 | 779 | 	if (log->slot >= KVM_MEMORY_SLOTS) | 
 | 780 | 		goto out; | 
 | 781 |  | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 782 | 	memslot = &kvm->memslots->memslots[log->slot]; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 783 | 	r = -ENOENT; | 
 | 784 | 	if (!memslot->dirty_bitmap) | 
 | 785 | 		goto out; | 
 | 786 |  | 
| Takuya Yoshikawa | 87bf6e7 | 2010-04-12 19:35:35 +0900 | [diff] [blame] | 787 | 	n = kvm_dirty_bitmap_bytes(memslot); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 788 |  | 
| Uri Lublin | cd1a4a9 | 2007-02-22 16:43:09 +0200 | [diff] [blame] | 789 | 	for (i = 0; !any && i < n/sizeof(long); ++i) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 790 | 		any = memslot->dirty_bitmap[i]; | 
 | 791 |  | 
 | 792 | 	r = -EFAULT; | 
 | 793 | 	if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n)) | 
 | 794 | 		goto out; | 
 | 795 |  | 
| Zhang Xiantao | 5bb064d | 2007-11-18 20:29:43 +0800 | [diff] [blame] | 796 | 	if (any) | 
 | 797 | 		*is_dirty = 1; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 798 |  | 
 | 799 | 	r = 0; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 800 | out: | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 801 | 	return r; | 
 | 802 | } | 
 | 803 |  | 
| Marcelo Tosatti | 54dee99 | 2009-06-11 12:07:44 -0300 | [diff] [blame] | 804 | void kvm_disable_largepages(void) | 
 | 805 | { | 
 | 806 | 	largepages_enabled = false; | 
 | 807 | } | 
 | 808 | EXPORT_SYMBOL_GPL(kvm_disable_largepages); | 
 | 809 |  | 
| Izik Eidus | cea7bb2 | 2007-10-17 19:17:48 +0200 | [diff] [blame] | 810 | int is_error_page(struct page *page) | 
 | 811 | { | 
 | 812 | 	return page == bad_page; | 
 | 813 | } | 
 | 814 | EXPORT_SYMBOL_GPL(is_error_page); | 
 | 815 |  | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 816 | int is_error_pfn(pfn_t pfn) | 
 | 817 | { | 
 | 818 | 	return pfn == bad_pfn; | 
 | 819 | } | 
 | 820 | EXPORT_SYMBOL_GPL(is_error_pfn); | 
 | 821 |  | 
| Izik Eidus | f9d46eb | 2007-11-11 22:02:22 +0200 | [diff] [blame] | 822 | static inline unsigned long bad_hva(void) | 
 | 823 | { | 
 | 824 | 	return PAGE_OFFSET; | 
 | 825 | } | 
 | 826 |  | 
 | 827 | int kvm_is_error_hva(unsigned long addr) | 
 | 828 | { | 
 | 829 | 	return addr == bad_hva(); | 
 | 830 | } | 
 | 831 | EXPORT_SYMBOL_GPL(kvm_is_error_hva); | 
 | 832 |  | 
| Izik Eidus | 2843099 | 2008-10-03 17:40:32 +0300 | [diff] [blame] | 833 | struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 834 | { | 
 | 835 | 	int i; | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 836 | 	struct kvm_memslots *slots = rcu_dereference(kvm->memslots); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 837 |  | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 838 | 	for (i = 0; i < slots->nmemslots; ++i) { | 
 | 839 | 		struct kvm_memory_slot *memslot = &slots->memslots[i]; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 840 |  | 
 | 841 | 		if (gfn >= memslot->base_gfn | 
 | 842 | 		    && gfn < memslot->base_gfn + memslot->npages) | 
 | 843 | 			return memslot; | 
 | 844 | 	} | 
| Al Viro | 8b6d44c | 2007-02-09 16:38:40 +0000 | [diff] [blame] | 845 | 	return NULL; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 846 | } | 
| Izik Eidus | 2843099 | 2008-10-03 17:40:32 +0300 | [diff] [blame] | 847 | EXPORT_SYMBOL_GPL(gfn_to_memslot_unaliased); | 
| Avi Kivity | e820754 | 2007-03-30 16:54:30 +0300 | [diff] [blame] | 848 |  | 
 | 849 | struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) | 
 | 850 | { | 
 | 851 | 	gfn = unalias_gfn(kvm, gfn); | 
| Izik Eidus | 2843099 | 2008-10-03 17:40:32 +0300 | [diff] [blame] | 852 | 	return gfn_to_memslot_unaliased(kvm, gfn); | 
| Avi Kivity | e820754 | 2007-03-30 16:54:30 +0300 | [diff] [blame] | 853 | } | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 854 |  | 
| Izik Eidus | e0d62c7 | 2007-10-24 23:57:46 +0200 | [diff] [blame] | 855 | int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) | 
 | 856 | { | 
 | 857 | 	int i; | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 858 | 	struct kvm_memslots *slots = rcu_dereference(kvm->memslots); | 
| Izik Eidus | e0d62c7 | 2007-10-24 23:57:46 +0200 | [diff] [blame] | 859 |  | 
| Marcelo Tosatti | a983fb2 | 2009-12-23 14:35:23 -0200 | [diff] [blame] | 860 | 	gfn = unalias_gfn_instantiation(kvm, gfn); | 
| Izik Eidus | e0d62c7 | 2007-10-24 23:57:46 +0200 | [diff] [blame] | 861 | 	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { | 
| Marcelo Tosatti | 46a26bf | 2009-12-23 14:35:16 -0200 | [diff] [blame] | 862 | 		struct kvm_memory_slot *memslot = &slots->memslots[i]; | 
| Izik Eidus | e0d62c7 | 2007-10-24 23:57:46 +0200 | [diff] [blame] | 863 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 864 | 		if (memslot->flags & KVM_MEMSLOT_INVALID) | 
 | 865 | 			continue; | 
 | 866 |  | 
| Izik Eidus | e0d62c7 | 2007-10-24 23:57:46 +0200 | [diff] [blame] | 867 | 		if (gfn >= memslot->base_gfn | 
 | 868 | 		    && gfn < memslot->base_gfn + memslot->npages) | 
 | 869 | 			return 1; | 
 | 870 | 	} | 
 | 871 | 	return 0; | 
 | 872 | } | 
 | 873 | EXPORT_SYMBOL_GPL(kvm_is_visible_gfn); | 
 | 874 |  | 
| Joerg Roedel | 8f0b1ab | 2010-01-28 12:37:56 +0100 | [diff] [blame] | 875 | unsigned long kvm_host_page_size(struct kvm *kvm, gfn_t gfn) | 
 | 876 | { | 
 | 877 | 	struct vm_area_struct *vma; | 
 | 878 | 	unsigned long addr, size; | 
 | 879 |  | 
 | 880 | 	size = PAGE_SIZE; | 
 | 881 |  | 
 | 882 | 	addr = gfn_to_hva(kvm, gfn); | 
 | 883 | 	if (kvm_is_error_hva(addr)) | 
 | 884 | 		return PAGE_SIZE; | 
 | 885 |  | 
 | 886 | 	down_read(¤t->mm->mmap_sem); | 
 | 887 | 	vma = find_vma(current->mm, addr); | 
 | 888 | 	if (!vma) | 
 | 889 | 		goto out; | 
 | 890 |  | 
 | 891 | 	size = vma_kernel_pagesize(vma); | 
 | 892 |  | 
 | 893 | out: | 
 | 894 | 	up_read(¤t->mm->mmap_sem); | 
 | 895 |  | 
 | 896 | 	return size; | 
 | 897 | } | 
 | 898 |  | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 899 | int memslot_id(struct kvm *kvm, gfn_t gfn) | 
 | 900 | { | 
 | 901 | 	int i; | 
 | 902 | 	struct kvm_memslots *slots = rcu_dereference(kvm->memslots); | 
 | 903 | 	struct kvm_memory_slot *memslot = NULL; | 
 | 904 |  | 
 | 905 | 	gfn = unalias_gfn(kvm, gfn); | 
 | 906 | 	for (i = 0; i < slots->nmemslots; ++i) { | 
 | 907 | 		memslot = &slots->memslots[i]; | 
 | 908 |  | 
 | 909 | 		if (gfn >= memslot->base_gfn | 
 | 910 | 		    && gfn < memslot->base_gfn + memslot->npages) | 
 | 911 | 			break; | 
 | 912 | 	} | 
 | 913 |  | 
 | 914 | 	return memslot - slots->memslots; | 
 | 915 | } | 
 | 916 |  | 
| Marcelo Tosatti | 05da455 | 2008-02-23 11:44:30 -0300 | [diff] [blame] | 917 | unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) | 
| Izik Eidus | 539cb66 | 2007-11-11 22:05:04 +0200 | [diff] [blame] | 918 | { | 
 | 919 | 	struct kvm_memory_slot *slot; | 
 | 920 |  | 
| Marcelo Tosatti | a983fb2 | 2009-12-23 14:35:23 -0200 | [diff] [blame] | 921 | 	gfn = unalias_gfn_instantiation(kvm, gfn); | 
| Izik Eidus | 2843099 | 2008-10-03 17:40:32 +0300 | [diff] [blame] | 922 | 	slot = gfn_to_memslot_unaliased(kvm, gfn); | 
| Marcelo Tosatti | bc6678a | 2009-12-23 14:35:21 -0200 | [diff] [blame] | 923 | 	if (!slot || slot->flags & KVM_MEMSLOT_INVALID) | 
| Izik Eidus | 539cb66 | 2007-11-11 22:05:04 +0200 | [diff] [blame] | 924 | 		return bad_hva(); | 
 | 925 | 	return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE); | 
 | 926 | } | 
| Sheng Yang | 0d15029 | 2008-04-25 21:44:50 +0800 | [diff] [blame] | 927 | EXPORT_SYMBOL_GPL(gfn_to_hva); | 
| Izik Eidus | 539cb66 | 2007-11-11 22:05:04 +0200 | [diff] [blame] | 928 |  | 
| Marcelo Tosatti | 506f0d6 | 2009-12-23 14:35:19 -0200 | [diff] [blame] | 929 | static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr) | 
| Avi Kivity | 954bbbc2 | 2007-03-30 14:02:32 +0300 | [diff] [blame] | 930 | { | 
| Anthony Liguori | 8d4e128 | 2007-10-18 09:59:34 -0500 | [diff] [blame] | 931 | 	struct page *page[1]; | 
 | 932 | 	int npages; | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 933 | 	pfn_t pfn; | 
| Avi Kivity | 954bbbc2 | 2007-03-30 14:02:32 +0300 | [diff] [blame] | 934 |  | 
| Avi Kivity | 6039522 | 2007-10-21 11:03:36 +0200 | [diff] [blame] | 935 | 	might_sleep(); | 
 | 936 |  | 
| Marcelo Tosatti | 4c2155c | 2008-09-16 20:54:47 -0300 | [diff] [blame] | 937 | 	npages = get_user_pages_fast(addr, 1, 1, page); | 
| Izik Eidus | 539cb66 | 2007-11-11 22:05:04 +0200 | [diff] [blame] | 938 |  | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 939 | 	if (unlikely(npages != 1)) { | 
 | 940 | 		struct vm_area_struct *vma; | 
| Anthony Liguori | 8d4e128 | 2007-10-18 09:59:34 -0500 | [diff] [blame] | 941 |  | 
| Marcelo Tosatti | 4c2155c | 2008-09-16 20:54:47 -0300 | [diff] [blame] | 942 | 		down_read(¤t->mm->mmap_sem); | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 943 | 		vma = find_vma(current->mm, addr); | 
| Marcelo Tosatti | 4c2155c | 2008-09-16 20:54:47 -0300 | [diff] [blame] | 944 |  | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 945 | 		if (vma == NULL || addr < vma->vm_start || | 
 | 946 | 		    !(vma->vm_flags & VM_PFNMAP)) { | 
| Marcelo Tosatti | 4c2155c | 2008-09-16 20:54:47 -0300 | [diff] [blame] | 947 | 			up_read(¤t->mm->mmap_sem); | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 948 | 			get_page(bad_page); | 
 | 949 | 			return page_to_pfn(bad_page); | 
 | 950 | 		} | 
 | 951 |  | 
 | 952 | 		pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; | 
| Marcelo Tosatti | 4c2155c | 2008-09-16 20:54:47 -0300 | [diff] [blame] | 953 | 		up_read(¤t->mm->mmap_sem); | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 954 | 		BUG_ON(!kvm_is_mmio_pfn(pfn)); | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 955 | 	} else | 
 | 956 | 		pfn = page_to_pfn(page[0]); | 
 | 957 |  | 
 | 958 | 	return pfn; | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 959 | } | 
 | 960 |  | 
| Marcelo Tosatti | 506f0d6 | 2009-12-23 14:35:19 -0200 | [diff] [blame] | 961 | pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) | 
 | 962 | { | 
 | 963 | 	unsigned long addr; | 
 | 964 |  | 
 | 965 | 	addr = gfn_to_hva(kvm, gfn); | 
 | 966 | 	if (kvm_is_error_hva(addr)) { | 
 | 967 | 		get_page(bad_page); | 
 | 968 | 		return page_to_pfn(bad_page); | 
 | 969 | 	} | 
 | 970 |  | 
 | 971 | 	return hva_to_pfn(kvm, addr); | 
 | 972 | } | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 973 | EXPORT_SYMBOL_GPL(gfn_to_pfn); | 
 | 974 |  | 
| Marcelo Tosatti | 506f0d6 | 2009-12-23 14:35:19 -0200 | [diff] [blame] | 975 | static unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn) | 
 | 976 | { | 
 | 977 | 	return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE); | 
 | 978 | } | 
 | 979 |  | 
 | 980 | pfn_t gfn_to_pfn_memslot(struct kvm *kvm, | 
 | 981 | 			 struct kvm_memory_slot *slot, gfn_t gfn) | 
 | 982 | { | 
 | 983 | 	unsigned long addr = gfn_to_hva_memslot(slot, gfn); | 
 | 984 | 	return hva_to_pfn(kvm, addr); | 
 | 985 | } | 
 | 986 |  | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 987 | struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) | 
 | 988 | { | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 989 | 	pfn_t pfn; | 
 | 990 |  | 
 | 991 | 	pfn = gfn_to_pfn(kvm, gfn); | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 992 | 	if (!kvm_is_mmio_pfn(pfn)) | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 993 | 		return pfn_to_page(pfn); | 
 | 994 |  | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 995 | 	WARN_ON(kvm_is_mmio_pfn(pfn)); | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 996 |  | 
 | 997 | 	get_page(bad_page); | 
 | 998 | 	return bad_page; | 
| Avi Kivity | 954bbbc2 | 2007-03-30 14:02:32 +0300 | [diff] [blame] | 999 | } | 
| Anthony Liguori | aab61cc | 2007-10-29 15:15:20 -0500 | [diff] [blame] | 1000 |  | 
| Avi Kivity | 954bbbc2 | 2007-03-30 14:02:32 +0300 | [diff] [blame] | 1001 | EXPORT_SYMBOL_GPL(gfn_to_page); | 
 | 1002 |  | 
| Izik Eidus | b4231d6 | 2007-11-20 11:49:33 +0200 | [diff] [blame] | 1003 | void kvm_release_page_clean(struct page *page) | 
 | 1004 | { | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1005 | 	kvm_release_pfn_clean(page_to_pfn(page)); | 
| Izik Eidus | b4231d6 | 2007-11-20 11:49:33 +0200 | [diff] [blame] | 1006 | } | 
 | 1007 | EXPORT_SYMBOL_GPL(kvm_release_page_clean); | 
 | 1008 |  | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1009 | void kvm_release_pfn_clean(pfn_t pfn) | 
 | 1010 | { | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 1011 | 	if (!kvm_is_mmio_pfn(pfn)) | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 1012 | 		put_page(pfn_to_page(pfn)); | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1013 | } | 
 | 1014 | EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); | 
 | 1015 |  | 
| Izik Eidus | b4231d6 | 2007-11-20 11:49:33 +0200 | [diff] [blame] | 1016 | void kvm_release_page_dirty(struct page *page) | 
| Izik Eidus | 8a7ae05 | 2007-10-18 11:09:33 +0200 | [diff] [blame] | 1017 | { | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1018 | 	kvm_release_pfn_dirty(page_to_pfn(page)); | 
| Izik Eidus | 8a7ae05 | 2007-10-18 11:09:33 +0200 | [diff] [blame] | 1019 | } | 
| Izik Eidus | b4231d6 | 2007-11-20 11:49:33 +0200 | [diff] [blame] | 1020 | EXPORT_SYMBOL_GPL(kvm_release_page_dirty); | 
| Izik Eidus | 8a7ae05 | 2007-10-18 11:09:33 +0200 | [diff] [blame] | 1021 |  | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1022 | void kvm_release_pfn_dirty(pfn_t pfn) | 
 | 1023 | { | 
 | 1024 | 	kvm_set_pfn_dirty(pfn); | 
 | 1025 | 	kvm_release_pfn_clean(pfn); | 
 | 1026 | } | 
 | 1027 | EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); | 
 | 1028 |  | 
 | 1029 | void kvm_set_page_dirty(struct page *page) | 
 | 1030 | { | 
 | 1031 | 	kvm_set_pfn_dirty(page_to_pfn(page)); | 
 | 1032 | } | 
 | 1033 | EXPORT_SYMBOL_GPL(kvm_set_page_dirty); | 
 | 1034 |  | 
 | 1035 | void kvm_set_pfn_dirty(pfn_t pfn) | 
 | 1036 | { | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 1037 | 	if (!kvm_is_mmio_pfn(pfn)) { | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 1038 | 		struct page *page = pfn_to_page(pfn); | 
 | 1039 | 		if (!PageReserved(page)) | 
 | 1040 | 			SetPageDirty(page); | 
 | 1041 | 	} | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1042 | } | 
 | 1043 | EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty); | 
 | 1044 |  | 
 | 1045 | void kvm_set_pfn_accessed(pfn_t pfn) | 
 | 1046 | { | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 1047 | 	if (!kvm_is_mmio_pfn(pfn)) | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 1048 | 		mark_page_accessed(pfn_to_page(pfn)); | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1049 | } | 
 | 1050 | EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); | 
 | 1051 |  | 
 | 1052 | void kvm_get_pfn(pfn_t pfn) | 
 | 1053 | { | 
| Xiantao Zhang | c77fb9d | 2008-09-27 10:55:40 +0800 | [diff] [blame] | 1054 | 	if (!kvm_is_mmio_pfn(pfn)) | 
| Anthony Liguori | 2e2e373 | 2008-04-30 15:37:07 -0500 | [diff] [blame] | 1055 | 		get_page(pfn_to_page(pfn)); | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 1056 | } | 
 | 1057 | EXPORT_SYMBOL_GPL(kvm_get_pfn); | 
 | 1058 |  | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1059 | static int next_segment(unsigned long len, int offset) | 
 | 1060 | { | 
 | 1061 | 	if (len > PAGE_SIZE - offset) | 
 | 1062 | 		return PAGE_SIZE - offset; | 
 | 1063 | 	else | 
 | 1064 | 		return len; | 
 | 1065 | } | 
 | 1066 |  | 
 | 1067 | int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, | 
 | 1068 | 			int len) | 
 | 1069 | { | 
| Izik Eidus | e0506bc | 2007-11-11 22:10:22 +0200 | [diff] [blame] | 1070 | 	int r; | 
 | 1071 | 	unsigned long addr; | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1072 |  | 
| Izik Eidus | e0506bc | 2007-11-11 22:10:22 +0200 | [diff] [blame] | 1073 | 	addr = gfn_to_hva(kvm, gfn); | 
 | 1074 | 	if (kvm_is_error_hva(addr)) | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1075 | 		return -EFAULT; | 
| Izik Eidus | e0506bc | 2007-11-11 22:10:22 +0200 | [diff] [blame] | 1076 | 	r = copy_from_user(data, (void __user *)addr + offset, len); | 
 | 1077 | 	if (r) | 
 | 1078 | 		return -EFAULT; | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1079 | 	return 0; | 
 | 1080 | } | 
 | 1081 | EXPORT_SYMBOL_GPL(kvm_read_guest_page); | 
 | 1082 |  | 
 | 1083 | int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len) | 
 | 1084 | { | 
 | 1085 | 	gfn_t gfn = gpa >> PAGE_SHIFT; | 
 | 1086 | 	int seg; | 
 | 1087 | 	int offset = offset_in_page(gpa); | 
 | 1088 | 	int ret; | 
 | 1089 |  | 
 | 1090 | 	while ((seg = next_segment(len, offset)) != 0) { | 
 | 1091 | 		ret = kvm_read_guest_page(kvm, gfn, data, offset, seg); | 
 | 1092 | 		if (ret < 0) | 
 | 1093 | 			return ret; | 
 | 1094 | 		offset = 0; | 
 | 1095 | 		len -= seg; | 
 | 1096 | 		data += seg; | 
 | 1097 | 		++gfn; | 
 | 1098 | 	} | 
 | 1099 | 	return 0; | 
 | 1100 | } | 
 | 1101 | EXPORT_SYMBOL_GPL(kvm_read_guest); | 
 | 1102 |  | 
| Marcelo Tosatti | 7ec5458 | 2007-12-20 19:18:23 -0500 | [diff] [blame] | 1103 | int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data, | 
 | 1104 | 			  unsigned long len) | 
 | 1105 | { | 
 | 1106 | 	int r; | 
 | 1107 | 	unsigned long addr; | 
 | 1108 | 	gfn_t gfn = gpa >> PAGE_SHIFT; | 
 | 1109 | 	int offset = offset_in_page(gpa); | 
 | 1110 |  | 
 | 1111 | 	addr = gfn_to_hva(kvm, gfn); | 
 | 1112 | 	if (kvm_is_error_hva(addr)) | 
 | 1113 | 		return -EFAULT; | 
| Andrea Arcangeli | 0aac03f | 2008-01-30 19:57:35 +0100 | [diff] [blame] | 1114 | 	pagefault_disable(); | 
| Marcelo Tosatti | 7ec5458 | 2007-12-20 19:18:23 -0500 | [diff] [blame] | 1115 | 	r = __copy_from_user_inatomic(data, (void __user *)addr + offset, len); | 
| Andrea Arcangeli | 0aac03f | 2008-01-30 19:57:35 +0100 | [diff] [blame] | 1116 | 	pagefault_enable(); | 
| Marcelo Tosatti | 7ec5458 | 2007-12-20 19:18:23 -0500 | [diff] [blame] | 1117 | 	if (r) | 
 | 1118 | 		return -EFAULT; | 
 | 1119 | 	return 0; | 
 | 1120 | } | 
 | 1121 | EXPORT_SYMBOL(kvm_read_guest_atomic); | 
 | 1122 |  | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1123 | int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data, | 
 | 1124 | 			 int offset, int len) | 
 | 1125 | { | 
| Izik Eidus | e0506bc | 2007-11-11 22:10:22 +0200 | [diff] [blame] | 1126 | 	int r; | 
 | 1127 | 	unsigned long addr; | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1128 |  | 
| Izik Eidus | e0506bc | 2007-11-11 22:10:22 +0200 | [diff] [blame] | 1129 | 	addr = gfn_to_hva(kvm, gfn); | 
 | 1130 | 	if (kvm_is_error_hva(addr)) | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1131 | 		return -EFAULT; | 
| Izik Eidus | e0506bc | 2007-11-11 22:10:22 +0200 | [diff] [blame] | 1132 | 	r = copy_to_user((void __user *)addr + offset, data, len); | 
 | 1133 | 	if (r) | 
 | 1134 | 		return -EFAULT; | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1135 | 	mark_page_dirty(kvm, gfn); | 
 | 1136 | 	return 0; | 
 | 1137 | } | 
 | 1138 | EXPORT_SYMBOL_GPL(kvm_write_guest_page); | 
 | 1139 |  | 
 | 1140 | int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, | 
 | 1141 | 		    unsigned long len) | 
 | 1142 | { | 
 | 1143 | 	gfn_t gfn = gpa >> PAGE_SHIFT; | 
 | 1144 | 	int seg; | 
 | 1145 | 	int offset = offset_in_page(gpa); | 
 | 1146 | 	int ret; | 
 | 1147 |  | 
 | 1148 | 	while ((seg = next_segment(len, offset)) != 0) { | 
 | 1149 | 		ret = kvm_write_guest_page(kvm, gfn, data, offset, seg); | 
 | 1150 | 		if (ret < 0) | 
 | 1151 | 			return ret; | 
 | 1152 | 		offset = 0; | 
 | 1153 | 		len -= seg; | 
 | 1154 | 		data += seg; | 
 | 1155 | 		++gfn; | 
 | 1156 | 	} | 
 | 1157 | 	return 0; | 
 | 1158 | } | 
 | 1159 |  | 
 | 1160 | int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len) | 
 | 1161 | { | 
| Izik Eidus | 3e021bf | 2007-11-19 11:16:57 +0200 | [diff] [blame] | 1162 | 	return kvm_write_guest_page(kvm, gfn, empty_zero_page, offset, len); | 
| Izik Eidus | 195aefd | 2007-10-01 22:14:18 +0200 | [diff] [blame] | 1163 | } | 
 | 1164 | EXPORT_SYMBOL_GPL(kvm_clear_guest_page); | 
 | 1165 |  | 
 | 1166 | int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len) | 
 | 1167 | { | 
 | 1168 | 	gfn_t gfn = gpa >> PAGE_SHIFT; | 
 | 1169 | 	int seg; | 
 | 1170 | 	int offset = offset_in_page(gpa); | 
 | 1171 | 	int ret; | 
 | 1172 |  | 
 | 1173 |         while ((seg = next_segment(len, offset)) != 0) { | 
 | 1174 | 		ret = kvm_clear_guest_page(kvm, gfn, offset, seg); | 
 | 1175 | 		if (ret < 0) | 
 | 1176 | 			return ret; | 
 | 1177 | 		offset = 0; | 
 | 1178 | 		len -= seg; | 
 | 1179 | 		++gfn; | 
 | 1180 | 	} | 
 | 1181 | 	return 0; | 
 | 1182 | } | 
 | 1183 | EXPORT_SYMBOL_GPL(kvm_clear_guest); | 
 | 1184 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1185 | void mark_page_dirty(struct kvm *kvm, gfn_t gfn) | 
 | 1186 | { | 
| Nguyen Anh Quynh | 3138994 | 2007-06-05 10:35:19 +0300 | [diff] [blame] | 1187 | 	struct kvm_memory_slot *memslot; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1188 |  | 
| Uri Lublin | 3b6fff1 | 2007-10-30 10:42:09 +0200 | [diff] [blame] | 1189 | 	gfn = unalias_gfn(kvm, gfn); | 
| Izik Eidus | 2843099 | 2008-10-03 17:40:32 +0300 | [diff] [blame] | 1190 | 	memslot = gfn_to_memslot_unaliased(kvm, gfn); | 
| Rusty Russell | 7e9d619 | 2007-07-31 20:41:14 +1000 | [diff] [blame] | 1191 | 	if (memslot && memslot->dirty_bitmap) { | 
 | 1192 | 		unsigned long rel_gfn = gfn - memslot->base_gfn; | 
| Takuya Yoshikawa | 87bf6e7 | 2010-04-12 19:35:35 +0900 | [diff] [blame] | 1193 | 		unsigned long *p = memslot->dirty_bitmap + | 
 | 1194 | 					rel_gfn / BITS_PER_LONG; | 
 | 1195 | 		int offset = rel_gfn % BITS_PER_LONG; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1196 |  | 
| Rusty Russell | 7e9d619 | 2007-07-31 20:41:14 +1000 | [diff] [blame] | 1197 | 		/* avoid RMW */ | 
| Takuya Yoshikawa | 87bf6e7 | 2010-04-12 19:35:35 +0900 | [diff] [blame] | 1198 | 		if (!generic_test_le_bit(offset, p)) | 
 | 1199 | 			generic___set_le_bit(offset, p); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1200 | 	} | 
 | 1201 | } | 
 | 1202 |  | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 1203 | /* | 
 | 1204 |  * The vCPU has executed a HLT instruction with in-kernel mode enabled. | 
 | 1205 |  */ | 
| Hollis Blanchard | 8776e51 | 2007-10-31 17:24:24 -0500 | [diff] [blame] | 1206 | void kvm_vcpu_block(struct kvm_vcpu *vcpu) | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 1207 | { | 
| Marcelo Tosatti | e5c239c | 2008-05-08 19:47:01 -0300 | [diff] [blame] | 1208 | 	DEFINE_WAIT(wait); | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 1209 |  | 
| Marcelo Tosatti | e5c239c | 2008-05-08 19:47:01 -0300 | [diff] [blame] | 1210 | 	for (;;) { | 
 | 1211 | 		prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 1212 |  | 
| Gleb Natapov | a1b3710 | 2009-07-09 15:33:52 +0300 | [diff] [blame] | 1213 | 		if (kvm_arch_vcpu_runnable(vcpu)) { | 
| Marcelo Tosatti | d769017 | 2008-09-08 15:23:48 -0300 | [diff] [blame] | 1214 | 			set_bit(KVM_REQ_UNHALT, &vcpu->requests); | 
| Marcelo Tosatti | e5c239c | 2008-05-08 19:47:01 -0300 | [diff] [blame] | 1215 | 			break; | 
| Marcelo Tosatti | d769017 | 2008-09-08 15:23:48 -0300 | [diff] [blame] | 1216 | 		} | 
| Gleb Natapov | 09cec75 | 2009-03-23 15:11:44 +0200 | [diff] [blame] | 1217 | 		if (kvm_cpu_has_pending_timer(vcpu)) | 
 | 1218 | 			break; | 
| Marcelo Tosatti | e5c239c | 2008-05-08 19:47:01 -0300 | [diff] [blame] | 1219 | 		if (signal_pending(current)) | 
 | 1220 | 			break; | 
 | 1221 |  | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 1222 | 		schedule(); | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 1223 | 	} | 
 | 1224 |  | 
| Marcelo Tosatti | e5c239c | 2008-05-08 19:47:01 -0300 | [diff] [blame] | 1225 | 	finish_wait(&vcpu->wq, &wait); | 
| Eddie Dong | b6958ce | 2007-07-18 12:15:21 +0300 | [diff] [blame] | 1226 | } | 
 | 1227 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1228 | void kvm_resched(struct kvm_vcpu *vcpu) | 
 | 1229 | { | 
| Yaozu Dong | 3fca036 | 2007-04-25 16:49:19 +0300 | [diff] [blame] | 1230 | 	if (!need_resched()) | 
 | 1231 | 		return; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1232 | 	cond_resched(); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1233 | } | 
 | 1234 | EXPORT_SYMBOL_GPL(kvm_resched); | 
 | 1235 |  | 
| Zhai, Edwin | d255f4f | 2009-10-09 18:03:20 +0800 | [diff] [blame] | 1236 | void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu) | 
 | 1237 | { | 
 | 1238 | 	ktime_t expires; | 
 | 1239 | 	DEFINE_WAIT(wait); | 
 | 1240 |  | 
 | 1241 | 	prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); | 
 | 1242 |  | 
 | 1243 | 	/* Sleep for 100 us, and hope lock-holder got scheduled */ | 
 | 1244 | 	expires = ktime_add_ns(ktime_get(), 100000UL); | 
 | 1245 | 	schedule_hrtimeout(&expires, HRTIMER_MODE_ABS); | 
 | 1246 |  | 
 | 1247 | 	finish_wait(&vcpu->wq, &wait); | 
 | 1248 | } | 
 | 1249 | EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin); | 
 | 1250 |  | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1251 | static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 
| Avi Kivity | 9a2bb7f | 2007-02-22 12:58:31 +0200 | [diff] [blame] | 1252 | { | 
 | 1253 | 	struct kvm_vcpu *vcpu = vma->vm_file->private_data; | 
| Avi Kivity | 9a2bb7f | 2007-02-22 12:58:31 +0200 | [diff] [blame] | 1254 | 	struct page *page; | 
 | 1255 |  | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1256 | 	if (vmf->pgoff == 0) | 
| Avi Kivity | 039576c | 2007-03-20 12:46:50 +0200 | [diff] [blame] | 1257 | 		page = virt_to_page(vcpu->run); | 
| Avi Kivity | 0956676 | 2008-01-23 18:14:23 +0200 | [diff] [blame] | 1258 | #ifdef CONFIG_X86 | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1259 | 	else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET) | 
| Zhang Xiantao | ad312c7 | 2007-12-13 23:50:52 +0800 | [diff] [blame] | 1260 | 		page = virt_to_page(vcpu->arch.pio_data); | 
| Avi Kivity | 0956676 | 2008-01-23 18:14:23 +0200 | [diff] [blame] | 1261 | #endif | 
| Laurent Vivier | 5f94c17 | 2008-05-30 16:05:54 +0200 | [diff] [blame] | 1262 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | 
 | 1263 | 	else if (vmf->pgoff == KVM_COALESCED_MMIO_PAGE_OFFSET) | 
 | 1264 | 		page = virt_to_page(vcpu->kvm->coalesced_mmio_ring); | 
 | 1265 | #endif | 
| Avi Kivity | 039576c | 2007-03-20 12:46:50 +0200 | [diff] [blame] | 1266 | 	else | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1267 | 		return VM_FAULT_SIGBUS; | 
| Avi Kivity | 9a2bb7f | 2007-02-22 12:58:31 +0200 | [diff] [blame] | 1268 | 	get_page(page); | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1269 | 	vmf->page = page; | 
 | 1270 | 	return 0; | 
| Avi Kivity | 9a2bb7f | 2007-02-22 12:58:31 +0200 | [diff] [blame] | 1271 | } | 
 | 1272 |  | 
| Alexey Dobriyan | f0f37e2 | 2009-09-27 22:29:37 +0400 | [diff] [blame] | 1273 | static const struct vm_operations_struct kvm_vcpu_vm_ops = { | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1274 | 	.fault = kvm_vcpu_fault, | 
| Avi Kivity | 9a2bb7f | 2007-02-22 12:58:31 +0200 | [diff] [blame] | 1275 | }; | 
 | 1276 |  | 
 | 1277 | static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma) | 
 | 1278 | { | 
 | 1279 | 	vma->vm_ops = &kvm_vcpu_vm_ops; | 
 | 1280 | 	return 0; | 
 | 1281 | } | 
 | 1282 |  | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1283 | static int kvm_vcpu_release(struct inode *inode, struct file *filp) | 
 | 1284 | { | 
 | 1285 | 	struct kvm_vcpu *vcpu = filp->private_data; | 
 | 1286 |  | 
| Al Viro | 66c0b39 | 2008-04-19 20:33:56 +0100 | [diff] [blame] | 1287 | 	kvm_put_kvm(vcpu->kvm); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1288 | 	return 0; | 
 | 1289 | } | 
 | 1290 |  | 
| Christian Borntraeger | 3d3aab1 | 2008-12-02 11:17:32 +0100 | [diff] [blame] | 1291 | static struct file_operations kvm_vcpu_fops = { | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1292 | 	.release        = kvm_vcpu_release, | 
 | 1293 | 	.unlocked_ioctl = kvm_vcpu_ioctl, | 
 | 1294 | 	.compat_ioctl   = kvm_vcpu_ioctl, | 
| Avi Kivity | 9a2bb7f | 2007-02-22 12:58:31 +0200 | [diff] [blame] | 1295 | 	.mmap           = kvm_vcpu_mmap, | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1296 | }; | 
 | 1297 |  | 
 | 1298 | /* | 
 | 1299 |  * Allocates an inode for the vcpu. | 
 | 1300 |  */ | 
 | 1301 | static int create_vcpu_fd(struct kvm_vcpu *vcpu) | 
 | 1302 | { | 
| Roland Dreier | 628ff7c | 2009-12-18 09:41:24 -0800 | [diff] [blame] | 1303 | 	return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, O_RDWR); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1304 | } | 
 | 1305 |  | 
| Avi Kivity | c5ea766 | 2007-02-20 18:41:05 +0200 | [diff] [blame] | 1306 | /* | 
 | 1307 |  * Creates some virtual cpus.  Good luck creating more than one. | 
 | 1308 |  */ | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1309 | static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) | 
| Avi Kivity | c5ea766 | 2007-02-20 18:41:05 +0200 | [diff] [blame] | 1310 | { | 
 | 1311 | 	int r; | 
| Gleb Natapov | 988a2ca | 2009-06-09 15:56:29 +0300 | [diff] [blame] | 1312 | 	struct kvm_vcpu *vcpu, *v; | 
| Avi Kivity | c5ea766 | 2007-02-20 18:41:05 +0200 | [diff] [blame] | 1313 |  | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1314 | 	vcpu = kvm_arch_vcpu_create(kvm, id); | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 1315 | 	if (IS_ERR(vcpu)) | 
 | 1316 | 		return PTR_ERR(vcpu); | 
| Avi Kivity | c5ea766 | 2007-02-20 18:41:05 +0200 | [diff] [blame] | 1317 |  | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 1318 | 	preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); | 
 | 1319 |  | 
| Avi Kivity | 26e5215 | 2007-11-20 15:30:24 +0200 | [diff] [blame] | 1320 | 	r = kvm_arch_vcpu_setup(vcpu); | 
 | 1321 | 	if (r) | 
| Glauber Costa | 7d8fece | 2008-09-17 23:16:59 -0300 | [diff] [blame] | 1322 | 		return r; | 
| Avi Kivity | 26e5215 | 2007-11-20 15:30:24 +0200 | [diff] [blame] | 1323 |  | 
| Shaohua Li | 11ec280 | 2007-07-23 14:51:37 +0800 | [diff] [blame] | 1324 | 	mutex_lock(&kvm->lock); | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1325 | 	if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) { | 
 | 1326 | 		r = -EINVAL; | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 1327 | 		goto vcpu_destroy; | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 1328 | 	} | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1329 |  | 
| Gleb Natapov | 988a2ca | 2009-06-09 15:56:29 +0300 | [diff] [blame] | 1330 | 	kvm_for_each_vcpu(r, v, kvm) | 
 | 1331 | 		if (v->vcpu_id == id) { | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1332 | 			r = -EEXIST; | 
 | 1333 | 			goto vcpu_destroy; | 
 | 1334 | 		} | 
 | 1335 |  | 
 | 1336 | 	BUG_ON(kvm->vcpus[atomic_read(&kvm->online_vcpus)]); | 
| Rusty Russell | fb3f0f5 | 2007-07-27 17:16:56 +1000 | [diff] [blame] | 1337 |  | 
 | 1338 | 	/* Now it's all set up, let userspace reach it */ | 
| Al Viro | 66c0b39 | 2008-04-19 20:33:56 +0100 | [diff] [blame] | 1339 | 	kvm_get_kvm(kvm); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1340 | 	r = create_vcpu_fd(vcpu); | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1341 | 	if (r < 0) { | 
 | 1342 | 		kvm_put_kvm(kvm); | 
 | 1343 | 		goto vcpu_destroy; | 
 | 1344 | 	} | 
 | 1345 |  | 
 | 1346 | 	kvm->vcpus[atomic_read(&kvm->online_vcpus)] = vcpu; | 
 | 1347 | 	smp_wmb(); | 
 | 1348 | 	atomic_inc(&kvm->online_vcpus); | 
 | 1349 |  | 
 | 1350 | #ifdef CONFIG_KVM_APIC_ARCHITECTURE | 
 | 1351 | 	if (kvm->bsp_vcpu_id == id) | 
 | 1352 | 		kvm->bsp_vcpu = vcpu; | 
 | 1353 | #endif | 
 | 1354 | 	mutex_unlock(&kvm->lock); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1355 | 	return r; | 
| Avi Kivity | c5ea766 | 2007-02-20 18:41:05 +0200 | [diff] [blame] | 1356 |  | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 1357 | vcpu_destroy: | 
| Glauber Costa | 7d8fece | 2008-09-17 23:16:59 -0300 | [diff] [blame] | 1358 | 	mutex_unlock(&kvm->lock); | 
| Hollis Blanchard | d40ccc6 | 2007-11-19 14:04:43 -0600 | [diff] [blame] | 1359 | 	kvm_arch_vcpu_destroy(vcpu); | 
| Avi Kivity | c5ea766 | 2007-02-20 18:41:05 +0200 | [diff] [blame] | 1360 | 	return r; | 
 | 1361 | } | 
 | 1362 |  | 
| Avi Kivity | 1961d27 | 2007-03-05 19:46:05 +0200 | [diff] [blame] | 1363 | static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) | 
 | 1364 | { | 
 | 1365 | 	if (sigset) { | 
 | 1366 | 		sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); | 
 | 1367 | 		vcpu->sigset_active = 1; | 
 | 1368 | 		vcpu->sigset = *sigset; | 
 | 1369 | 	} else | 
 | 1370 | 		vcpu->sigset_active = 0; | 
 | 1371 | 	return 0; | 
 | 1372 | } | 
 | 1373 |  | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1374 | static long kvm_vcpu_ioctl(struct file *filp, | 
 | 1375 | 			   unsigned int ioctl, unsigned long arg) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1376 | { | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1377 | 	struct kvm_vcpu *vcpu = filp->private_data; | 
| Al Viro | 2f36698 | 2007-02-09 16:38:35 +0000 | [diff] [blame] | 1378 | 	void __user *argp = (void __user *)arg; | 
| Carsten Otte | 313a3dc | 2007-10-11 19:16:52 +0200 | [diff] [blame] | 1379 | 	int r; | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1380 | 	struct kvm_fpu *fpu = NULL; | 
 | 1381 | 	struct kvm_sregs *kvm_sregs = NULL; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1382 |  | 
| Avi Kivity | 6d4e4c4 | 2007-11-21 16:41:05 +0200 | [diff] [blame] | 1383 | 	if (vcpu->kvm->mm != current->mm) | 
 | 1384 | 		return -EIO; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1385 | 	switch (ioctl) { | 
| Avi Kivity | 9a2bb7f | 2007-02-22 12:58:31 +0200 | [diff] [blame] | 1386 | 	case KVM_RUN: | 
| Avi Kivity | f0fe510 | 2007-03-07 13:11:17 +0200 | [diff] [blame] | 1387 | 		r = -EINVAL; | 
 | 1388 | 		if (arg) | 
 | 1389 | 			goto out; | 
| Hollis Blanchard | b6c7a5d | 2007-11-01 14:16:10 -0500 | [diff] [blame] | 1390 | 		r = kvm_arch_vcpu_ioctl_run(vcpu, vcpu->run); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1391 | 		break; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1392 | 	case KVM_GET_REGS: { | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1393 | 		struct kvm_regs *kvm_regs; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1394 |  | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1395 | 		r = -ENOMEM; | 
 | 1396 | 		kvm_regs = kzalloc(sizeof(struct kvm_regs), GFP_KERNEL); | 
 | 1397 | 		if (!kvm_regs) | 
 | 1398 | 			goto out; | 
 | 1399 | 		r = kvm_arch_vcpu_ioctl_get_regs(vcpu, kvm_regs); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1400 | 		if (r) | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1401 | 			goto out_free1; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1402 | 		r = -EFAULT; | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1403 | 		if (copy_to_user(argp, kvm_regs, sizeof(struct kvm_regs))) | 
 | 1404 | 			goto out_free1; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1405 | 		r = 0; | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1406 | out_free1: | 
 | 1407 | 		kfree(kvm_regs); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1408 | 		break; | 
 | 1409 | 	} | 
 | 1410 | 	case KVM_SET_REGS: { | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1411 | 		struct kvm_regs *kvm_regs; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1412 |  | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1413 | 		r = -ENOMEM; | 
 | 1414 | 		kvm_regs = kzalloc(sizeof(struct kvm_regs), GFP_KERNEL); | 
 | 1415 | 		if (!kvm_regs) | 
 | 1416 | 			goto out; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1417 | 		r = -EFAULT; | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1418 | 		if (copy_from_user(kvm_regs, argp, sizeof(struct kvm_regs))) | 
 | 1419 | 			goto out_free2; | 
 | 1420 | 		r = kvm_arch_vcpu_ioctl_set_regs(vcpu, kvm_regs); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1421 | 		if (r) | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1422 | 			goto out_free2; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1423 | 		r = 0; | 
| Xiantao Zhang | 3e4bb3a | 2008-02-25 18:52:20 +0800 | [diff] [blame] | 1424 | out_free2: | 
 | 1425 | 		kfree(kvm_regs); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1426 | 		break; | 
 | 1427 | 	} | 
 | 1428 | 	case KVM_GET_SREGS: { | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1429 | 		kvm_sregs = kzalloc(sizeof(struct kvm_sregs), GFP_KERNEL); | 
 | 1430 | 		r = -ENOMEM; | 
 | 1431 | 		if (!kvm_sregs) | 
 | 1432 | 			goto out; | 
 | 1433 | 		r = kvm_arch_vcpu_ioctl_get_sregs(vcpu, kvm_sregs); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1434 | 		if (r) | 
 | 1435 | 			goto out; | 
 | 1436 | 		r = -EFAULT; | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1437 | 		if (copy_to_user(argp, kvm_sregs, sizeof(struct kvm_sregs))) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1438 | 			goto out; | 
 | 1439 | 		r = 0; | 
 | 1440 | 		break; | 
 | 1441 | 	} | 
 | 1442 | 	case KVM_SET_SREGS: { | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1443 | 		kvm_sregs = kmalloc(sizeof(struct kvm_sregs), GFP_KERNEL); | 
 | 1444 | 		r = -ENOMEM; | 
 | 1445 | 		if (!kvm_sregs) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1446 | 			goto out; | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1447 | 		r = -EFAULT; | 
 | 1448 | 		if (copy_from_user(kvm_sregs, argp, sizeof(struct kvm_sregs))) | 
 | 1449 | 			goto out; | 
 | 1450 | 		r = kvm_arch_vcpu_ioctl_set_sregs(vcpu, kvm_sregs); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1451 | 		if (r) | 
 | 1452 | 			goto out; | 
 | 1453 | 		r = 0; | 
 | 1454 | 		break; | 
 | 1455 | 	} | 
| Marcelo Tosatti | 62d9f0d | 2008-04-11 13:24:45 -0300 | [diff] [blame] | 1456 | 	case KVM_GET_MP_STATE: { | 
 | 1457 | 		struct kvm_mp_state mp_state; | 
 | 1458 |  | 
 | 1459 | 		r = kvm_arch_vcpu_ioctl_get_mpstate(vcpu, &mp_state); | 
 | 1460 | 		if (r) | 
 | 1461 | 			goto out; | 
 | 1462 | 		r = -EFAULT; | 
 | 1463 | 		if (copy_to_user(argp, &mp_state, sizeof mp_state)) | 
 | 1464 | 			goto out; | 
 | 1465 | 		r = 0; | 
 | 1466 | 		break; | 
 | 1467 | 	} | 
 | 1468 | 	case KVM_SET_MP_STATE: { | 
 | 1469 | 		struct kvm_mp_state mp_state; | 
 | 1470 |  | 
 | 1471 | 		r = -EFAULT; | 
 | 1472 | 		if (copy_from_user(&mp_state, argp, sizeof mp_state)) | 
 | 1473 | 			goto out; | 
 | 1474 | 		r = kvm_arch_vcpu_ioctl_set_mpstate(vcpu, &mp_state); | 
 | 1475 | 		if (r) | 
 | 1476 | 			goto out; | 
 | 1477 | 		r = 0; | 
 | 1478 | 		break; | 
 | 1479 | 	} | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1480 | 	case KVM_TRANSLATE: { | 
 | 1481 | 		struct kvm_translation tr; | 
 | 1482 |  | 
 | 1483 | 		r = -EFAULT; | 
| Al Viro | 2f36698 | 2007-02-09 16:38:35 +0000 | [diff] [blame] | 1484 | 		if (copy_from_user(&tr, argp, sizeof tr)) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1485 | 			goto out; | 
| Zhang Xiantao | 8b00679 | 2007-11-16 13:05:55 +0800 | [diff] [blame] | 1486 | 		r = kvm_arch_vcpu_ioctl_translate(vcpu, &tr); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1487 | 		if (r) | 
 | 1488 | 			goto out; | 
 | 1489 | 		r = -EFAULT; | 
| Al Viro | 2f36698 | 2007-02-09 16:38:35 +0000 | [diff] [blame] | 1490 | 		if (copy_to_user(argp, &tr, sizeof tr)) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1491 | 			goto out; | 
 | 1492 | 		r = 0; | 
 | 1493 | 		break; | 
 | 1494 | 	} | 
| Jan Kiszka | d0bfb94 | 2008-12-15 13:52:10 +0100 | [diff] [blame] | 1495 | 	case KVM_SET_GUEST_DEBUG: { | 
 | 1496 | 		struct kvm_guest_debug dbg; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1497 |  | 
 | 1498 | 		r = -EFAULT; | 
| Al Viro | 2f36698 | 2007-02-09 16:38:35 +0000 | [diff] [blame] | 1499 | 		if (copy_from_user(&dbg, argp, sizeof dbg)) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1500 | 			goto out; | 
| Jan Kiszka | d0bfb94 | 2008-12-15 13:52:10 +0100 | [diff] [blame] | 1501 | 		r = kvm_arch_vcpu_ioctl_set_guest_debug(vcpu, &dbg); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1502 | 		if (r) | 
 | 1503 | 			goto out; | 
 | 1504 | 		r = 0; | 
 | 1505 | 		break; | 
 | 1506 | 	} | 
| Avi Kivity | 1961d27 | 2007-03-05 19:46:05 +0200 | [diff] [blame] | 1507 | 	case KVM_SET_SIGNAL_MASK: { | 
 | 1508 | 		struct kvm_signal_mask __user *sigmask_arg = argp; | 
 | 1509 | 		struct kvm_signal_mask kvm_sigmask; | 
 | 1510 | 		sigset_t sigset, *p; | 
 | 1511 |  | 
 | 1512 | 		p = NULL; | 
 | 1513 | 		if (argp) { | 
 | 1514 | 			r = -EFAULT; | 
 | 1515 | 			if (copy_from_user(&kvm_sigmask, argp, | 
 | 1516 | 					   sizeof kvm_sigmask)) | 
 | 1517 | 				goto out; | 
 | 1518 | 			r = -EINVAL; | 
 | 1519 | 			if (kvm_sigmask.len != sizeof sigset) | 
 | 1520 | 				goto out; | 
 | 1521 | 			r = -EFAULT; | 
 | 1522 | 			if (copy_from_user(&sigset, sigmask_arg->sigset, | 
 | 1523 | 					   sizeof sigset)) | 
 | 1524 | 				goto out; | 
 | 1525 | 			p = &sigset; | 
 | 1526 | 		} | 
 | 1527 | 		r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); | 
 | 1528 | 		break; | 
 | 1529 | 	} | 
| Avi Kivity | b883673 | 2007-04-01 16:34:31 +0300 | [diff] [blame] | 1530 | 	case KVM_GET_FPU: { | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1531 | 		fpu = kzalloc(sizeof(struct kvm_fpu), GFP_KERNEL); | 
 | 1532 | 		r = -ENOMEM; | 
 | 1533 | 		if (!fpu) | 
 | 1534 | 			goto out; | 
 | 1535 | 		r = kvm_arch_vcpu_ioctl_get_fpu(vcpu, fpu); | 
| Avi Kivity | b883673 | 2007-04-01 16:34:31 +0300 | [diff] [blame] | 1536 | 		if (r) | 
 | 1537 | 			goto out; | 
 | 1538 | 		r = -EFAULT; | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1539 | 		if (copy_to_user(argp, fpu, sizeof(struct kvm_fpu))) | 
| Avi Kivity | b883673 | 2007-04-01 16:34:31 +0300 | [diff] [blame] | 1540 | 			goto out; | 
 | 1541 | 		r = 0; | 
 | 1542 | 		break; | 
 | 1543 | 	} | 
 | 1544 | 	case KVM_SET_FPU: { | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1545 | 		fpu = kmalloc(sizeof(struct kvm_fpu), GFP_KERNEL); | 
 | 1546 | 		r = -ENOMEM; | 
 | 1547 | 		if (!fpu) | 
| Avi Kivity | b883673 | 2007-04-01 16:34:31 +0300 | [diff] [blame] | 1548 | 			goto out; | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1549 | 		r = -EFAULT; | 
 | 1550 | 		if (copy_from_user(fpu, argp, sizeof(struct kvm_fpu))) | 
 | 1551 | 			goto out; | 
 | 1552 | 		r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, fpu); | 
| Avi Kivity | b883673 | 2007-04-01 16:34:31 +0300 | [diff] [blame] | 1553 | 		if (r) | 
 | 1554 | 			goto out; | 
 | 1555 | 		r = 0; | 
 | 1556 | 		break; | 
 | 1557 | 	} | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1558 | 	default: | 
| Carsten Otte | 313a3dc | 2007-10-11 19:16:52 +0200 | [diff] [blame] | 1559 | 		r = kvm_arch_vcpu_ioctl(filp, ioctl, arg); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1560 | 	} | 
 | 1561 | out: | 
| Dave Hansen | fa3795a | 2008-08-11 10:01:46 -0700 | [diff] [blame] | 1562 | 	kfree(fpu); | 
 | 1563 | 	kfree(kvm_sregs); | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1564 | 	return r; | 
 | 1565 | } | 
 | 1566 |  | 
 | 1567 | static long kvm_vm_ioctl(struct file *filp, | 
 | 1568 | 			   unsigned int ioctl, unsigned long arg) | 
 | 1569 | { | 
 | 1570 | 	struct kvm *kvm = filp->private_data; | 
 | 1571 | 	void __user *argp = (void __user *)arg; | 
| Carsten Otte | 1fe779f | 2007-10-29 16:08:35 +0100 | [diff] [blame] | 1572 | 	int r; | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1573 |  | 
| Avi Kivity | 6d4e4c4 | 2007-11-21 16:41:05 +0200 | [diff] [blame] | 1574 | 	if (kvm->mm != current->mm) | 
 | 1575 | 		return -EIO; | 
| Avi Kivity | bccf215 | 2007-02-21 18:04:26 +0200 | [diff] [blame] | 1576 | 	switch (ioctl) { | 
 | 1577 | 	case KVM_CREATE_VCPU: | 
 | 1578 | 		r = kvm_vm_ioctl_create_vcpu(kvm, arg); | 
 | 1579 | 		if (r < 0) | 
 | 1580 | 			goto out; | 
 | 1581 | 		break; | 
| Izik Eidus | 6fc138d | 2007-10-09 19:20:39 +0200 | [diff] [blame] | 1582 | 	case KVM_SET_USER_MEMORY_REGION: { | 
 | 1583 | 		struct kvm_userspace_memory_region kvm_userspace_mem; | 
 | 1584 |  | 
 | 1585 | 		r = -EFAULT; | 
 | 1586 | 		if (copy_from_user(&kvm_userspace_mem, argp, | 
 | 1587 | 						sizeof kvm_userspace_mem)) | 
 | 1588 | 			goto out; | 
 | 1589 |  | 
 | 1590 | 		r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 1); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1591 | 		if (r) | 
 | 1592 | 			goto out; | 
 | 1593 | 		break; | 
 | 1594 | 	} | 
 | 1595 | 	case KVM_GET_DIRTY_LOG: { | 
 | 1596 | 		struct kvm_dirty_log log; | 
 | 1597 |  | 
 | 1598 | 		r = -EFAULT; | 
| Al Viro | 2f36698 | 2007-02-09 16:38:35 +0000 | [diff] [blame] | 1599 | 		if (copy_from_user(&log, argp, sizeof log)) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1600 | 			goto out; | 
| Avi Kivity | 2c6f5df | 2007-02-20 18:27:58 +0200 | [diff] [blame] | 1601 | 		r = kvm_vm_ioctl_get_dirty_log(kvm, &log); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1602 | 		if (r) | 
 | 1603 | 			goto out; | 
 | 1604 | 		break; | 
 | 1605 | 	} | 
| Laurent Vivier | 5f94c17 | 2008-05-30 16:05:54 +0200 | [diff] [blame] | 1606 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | 
 | 1607 | 	case KVM_REGISTER_COALESCED_MMIO: { | 
 | 1608 | 		struct kvm_coalesced_mmio_zone zone; | 
 | 1609 | 		r = -EFAULT; | 
 | 1610 | 		if (copy_from_user(&zone, argp, sizeof zone)) | 
 | 1611 | 			goto out; | 
 | 1612 | 		r = -ENXIO; | 
 | 1613 | 		r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone); | 
 | 1614 | 		if (r) | 
 | 1615 | 			goto out; | 
 | 1616 | 		r = 0; | 
 | 1617 | 		break; | 
 | 1618 | 	} | 
 | 1619 | 	case KVM_UNREGISTER_COALESCED_MMIO: { | 
 | 1620 | 		struct kvm_coalesced_mmio_zone zone; | 
 | 1621 | 		r = -EFAULT; | 
 | 1622 | 		if (copy_from_user(&zone, argp, sizeof zone)) | 
 | 1623 | 			goto out; | 
 | 1624 | 		r = -ENXIO; | 
 | 1625 | 		r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone); | 
 | 1626 | 		if (r) | 
 | 1627 | 			goto out; | 
 | 1628 | 		r = 0; | 
 | 1629 | 		break; | 
 | 1630 | 	} | 
 | 1631 | #endif | 
| Gregory Haskins | 721eecb | 2009-05-20 10:30:49 -0400 | [diff] [blame] | 1632 | 	case KVM_IRQFD: { | 
 | 1633 | 		struct kvm_irqfd data; | 
 | 1634 |  | 
 | 1635 | 		r = -EFAULT; | 
 | 1636 | 		if (copy_from_user(&data, argp, sizeof data)) | 
 | 1637 | 			goto out; | 
 | 1638 | 		r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags); | 
 | 1639 | 		break; | 
 | 1640 | 	} | 
| Gregory Haskins | d34e6b1 | 2009-07-07 17:08:49 -0400 | [diff] [blame] | 1641 | 	case KVM_IOEVENTFD: { | 
 | 1642 | 		struct kvm_ioeventfd data; | 
 | 1643 |  | 
 | 1644 | 		r = -EFAULT; | 
 | 1645 | 		if (copy_from_user(&data, argp, sizeof data)) | 
 | 1646 | 			goto out; | 
 | 1647 | 		r = kvm_ioeventfd(kvm, &data); | 
 | 1648 | 		break; | 
 | 1649 | 	} | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1650 | #ifdef CONFIG_KVM_APIC_ARCHITECTURE | 
 | 1651 | 	case KVM_SET_BOOT_CPU_ID: | 
 | 1652 | 		r = 0; | 
| Marcelo Tosatti | 894a9c5 | 2009-06-23 15:05:14 -0300 | [diff] [blame] | 1653 | 		mutex_lock(&kvm->lock); | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1654 | 		if (atomic_read(&kvm->online_vcpus) != 0) | 
 | 1655 | 			r = -EBUSY; | 
 | 1656 | 		else | 
 | 1657 | 			kvm->bsp_vcpu_id = arg; | 
| Marcelo Tosatti | 894a9c5 | 2009-06-23 15:05:14 -0300 | [diff] [blame] | 1658 | 		mutex_unlock(&kvm->lock); | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1659 | 		break; | 
 | 1660 | #endif | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1661 | 	default: | 
| Carsten Otte | 1fe779f | 2007-10-29 16:08:35 +0100 | [diff] [blame] | 1662 | 		r = kvm_arch_vm_ioctl(filp, ioctl, arg); | 
| Avi Kivity | bfd99ff | 2009-08-26 14:57:50 +0300 | [diff] [blame] | 1663 | 		if (r == -ENOTTY) | 
 | 1664 | 			r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg); | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1665 | 	} | 
 | 1666 | out: | 
 | 1667 | 	return r; | 
 | 1668 | } | 
 | 1669 |  | 
| Arnd Bergmann | 6ff5894 | 2009-10-22 14:19:27 +0200 | [diff] [blame] | 1670 | #ifdef CONFIG_COMPAT | 
 | 1671 | struct compat_kvm_dirty_log { | 
 | 1672 | 	__u32 slot; | 
 | 1673 | 	__u32 padding1; | 
 | 1674 | 	union { | 
 | 1675 | 		compat_uptr_t dirty_bitmap; /* one bit per page */ | 
 | 1676 | 		__u64 padding2; | 
 | 1677 | 	}; | 
 | 1678 | }; | 
 | 1679 |  | 
 | 1680 | static long kvm_vm_compat_ioctl(struct file *filp, | 
 | 1681 | 			   unsigned int ioctl, unsigned long arg) | 
 | 1682 | { | 
 | 1683 | 	struct kvm *kvm = filp->private_data; | 
 | 1684 | 	int r; | 
 | 1685 |  | 
 | 1686 | 	if (kvm->mm != current->mm) | 
 | 1687 | 		return -EIO; | 
 | 1688 | 	switch (ioctl) { | 
 | 1689 | 	case KVM_GET_DIRTY_LOG: { | 
 | 1690 | 		struct compat_kvm_dirty_log compat_log; | 
 | 1691 | 		struct kvm_dirty_log log; | 
 | 1692 |  | 
 | 1693 | 		r = -EFAULT; | 
 | 1694 | 		if (copy_from_user(&compat_log, (void __user *)arg, | 
 | 1695 | 				   sizeof(compat_log))) | 
 | 1696 | 			goto out; | 
 | 1697 | 		log.slot	 = compat_log.slot; | 
 | 1698 | 		log.padding1	 = compat_log.padding1; | 
 | 1699 | 		log.padding2	 = compat_log.padding2; | 
 | 1700 | 		log.dirty_bitmap = compat_ptr(compat_log.dirty_bitmap); | 
 | 1701 |  | 
 | 1702 | 		r = kvm_vm_ioctl_get_dirty_log(kvm, &log); | 
 | 1703 | 		if (r) | 
 | 1704 | 			goto out; | 
 | 1705 | 		break; | 
 | 1706 | 	} | 
 | 1707 | 	default: | 
 | 1708 | 		r = kvm_vm_ioctl(filp, ioctl, arg); | 
 | 1709 | 	} | 
 | 1710 |  | 
 | 1711 | out: | 
 | 1712 | 	return r; | 
 | 1713 | } | 
 | 1714 | #endif | 
 | 1715 |  | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1716 | static int kvm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1717 | { | 
| Marcelo Tosatti | 777b3f4 | 2008-09-16 20:54:46 -0300 | [diff] [blame] | 1718 | 	struct page *page[1]; | 
 | 1719 | 	unsigned long addr; | 
 | 1720 | 	int npages; | 
 | 1721 | 	gfn_t gfn = vmf->pgoff; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1722 | 	struct kvm *kvm = vma->vm_file->private_data; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1723 |  | 
| Marcelo Tosatti | 777b3f4 | 2008-09-16 20:54:46 -0300 | [diff] [blame] | 1724 | 	addr = gfn_to_hva(kvm, gfn); | 
 | 1725 | 	if (kvm_is_error_hva(addr)) | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1726 | 		return VM_FAULT_SIGBUS; | 
| Marcelo Tosatti | 777b3f4 | 2008-09-16 20:54:46 -0300 | [diff] [blame] | 1727 |  | 
 | 1728 | 	npages = get_user_pages(current, current->mm, addr, 1, 1, 0, page, | 
 | 1729 | 				NULL); | 
 | 1730 | 	if (unlikely(npages != 1)) | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1731 | 		return VM_FAULT_SIGBUS; | 
| Marcelo Tosatti | 777b3f4 | 2008-09-16 20:54:46 -0300 | [diff] [blame] | 1732 |  | 
 | 1733 | 	vmf->page = page[0]; | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1734 | 	return 0; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1735 | } | 
 | 1736 |  | 
| Alexey Dobriyan | f0f37e2 | 2009-09-27 22:29:37 +0400 | [diff] [blame] | 1737 | static const struct vm_operations_struct kvm_vm_vm_ops = { | 
| npiggin@suse.de | e4a533a | 2007-12-05 18:15:52 +1100 | [diff] [blame] | 1738 | 	.fault = kvm_vm_fault, | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1739 | }; | 
 | 1740 |  | 
 | 1741 | static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma) | 
 | 1742 | { | 
 | 1743 | 	vma->vm_ops = &kvm_vm_vm_ops; | 
 | 1744 | 	return 0; | 
 | 1745 | } | 
 | 1746 |  | 
| Christian Borntraeger | 3d3aab1 | 2008-12-02 11:17:32 +0100 | [diff] [blame] | 1747 | static struct file_operations kvm_vm_fops = { | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1748 | 	.release        = kvm_vm_release, | 
 | 1749 | 	.unlocked_ioctl = kvm_vm_ioctl, | 
| Arnd Bergmann | 6ff5894 | 2009-10-22 14:19:27 +0200 | [diff] [blame] | 1750 | #ifdef CONFIG_COMPAT | 
 | 1751 | 	.compat_ioctl   = kvm_vm_compat_ioctl, | 
 | 1752 | #endif | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1753 | 	.mmap           = kvm_vm_mmap, | 
 | 1754 | }; | 
 | 1755 |  | 
 | 1756 | static int kvm_dev_ioctl_create_vm(void) | 
 | 1757 | { | 
| Al Viro | 2030a42 | 2008-02-23 06:46:49 -0500 | [diff] [blame] | 1758 | 	int fd; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1759 | 	struct kvm *kvm; | 
 | 1760 |  | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1761 | 	kvm = kvm_create_vm(); | 
| Avi Kivity | d6d2816 | 2007-06-28 08:38:16 -0400 | [diff] [blame] | 1762 | 	if (IS_ERR(kvm)) | 
 | 1763 | 		return PTR_ERR(kvm); | 
| Roland Dreier | 628ff7c | 2009-12-18 09:41:24 -0800 | [diff] [blame] | 1764 | 	fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR); | 
| Al Viro | 2030a42 | 2008-02-23 06:46:49 -0500 | [diff] [blame] | 1765 | 	if (fd < 0) | 
| Al Viro | 66c0b39 | 2008-04-19 20:33:56 +0100 | [diff] [blame] | 1766 | 		kvm_put_kvm(kvm); | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1767 |  | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1768 | 	return fd; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1769 | } | 
 | 1770 |  | 
| Avi Kivity | 1a811b6 | 2008-12-08 18:25:27 +0200 | [diff] [blame] | 1771 | static long kvm_dev_ioctl_check_extension_generic(long arg) | 
 | 1772 | { | 
 | 1773 | 	switch (arg) { | 
| Avi Kivity | ca9edae | 2008-12-08 18:29:29 +0200 | [diff] [blame] | 1774 | 	case KVM_CAP_USER_MEMORY: | 
| Avi Kivity | 1a811b6 | 2008-12-08 18:25:27 +0200 | [diff] [blame] | 1775 | 	case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: | 
| Jan Kiszka | 4cd481f | 2009-04-13 11:59:32 +0200 | [diff] [blame] | 1776 | 	case KVM_CAP_JOIN_MEMORY_REGIONS_WORKS: | 
| Gleb Natapov | 73880c8 | 2009-06-09 15:56:28 +0300 | [diff] [blame] | 1777 | #ifdef CONFIG_KVM_APIC_ARCHITECTURE | 
 | 1778 | 	case KVM_CAP_SET_BOOT_CPU_ID: | 
 | 1779 | #endif | 
| Avi Kivity | a9c7399 | 2009-11-04 11:54:59 +0200 | [diff] [blame] | 1780 | 	case KVM_CAP_INTERNAL_ERROR_DATA: | 
| Avi Kivity | 1a811b6 | 2008-12-08 18:25:27 +0200 | [diff] [blame] | 1781 | 		return 1; | 
| Avi Kivity | 399ec80 | 2008-11-19 13:58:46 +0200 | [diff] [blame] | 1782 | #ifdef CONFIG_HAVE_KVM_IRQCHIP | 
 | 1783 | 	case KVM_CAP_IRQ_ROUTING: | 
| Sheng Yang | 3646314 | 2009-03-16 16:33:43 +0800 | [diff] [blame] | 1784 | 		return KVM_MAX_IRQ_ROUTES; | 
| Avi Kivity | 399ec80 | 2008-11-19 13:58:46 +0200 | [diff] [blame] | 1785 | #endif | 
| Avi Kivity | 1a811b6 | 2008-12-08 18:25:27 +0200 | [diff] [blame] | 1786 | 	default: | 
 | 1787 | 		break; | 
 | 1788 | 	} | 
 | 1789 | 	return kvm_dev_ioctl_check_extension(arg); | 
 | 1790 | } | 
 | 1791 |  | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1792 | static long kvm_dev_ioctl(struct file *filp, | 
 | 1793 | 			  unsigned int ioctl, unsigned long arg) | 
 | 1794 | { | 
| Avi Kivity | 07c45a3 | 2007-03-07 13:05:38 +0200 | [diff] [blame] | 1795 | 	long r = -EINVAL; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1796 |  | 
 | 1797 | 	switch (ioctl) { | 
 | 1798 | 	case KVM_GET_API_VERSION: | 
| Avi Kivity | f0fe510 | 2007-03-07 13:11:17 +0200 | [diff] [blame] | 1799 | 		r = -EINVAL; | 
 | 1800 | 		if (arg) | 
 | 1801 | 			goto out; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1802 | 		r = KVM_API_VERSION; | 
 | 1803 | 		break; | 
 | 1804 | 	case KVM_CREATE_VM: | 
| Avi Kivity | f0fe510 | 2007-03-07 13:11:17 +0200 | [diff] [blame] | 1805 | 		r = -EINVAL; | 
 | 1806 | 		if (arg) | 
 | 1807 | 			goto out; | 
| Avi Kivity | f17abe9 | 2007-02-21 19:28:04 +0200 | [diff] [blame] | 1808 | 		r = kvm_dev_ioctl_create_vm(); | 
 | 1809 | 		break; | 
| Zhang Xiantao | 018d00d | 2007-11-15 23:07:47 +0800 | [diff] [blame] | 1810 | 	case KVM_CHECK_EXTENSION: | 
| Avi Kivity | 1a811b6 | 2008-12-08 18:25:27 +0200 | [diff] [blame] | 1811 | 		r = kvm_dev_ioctl_check_extension_generic(arg); | 
| Avi Kivity | 5d308f4 | 2007-03-01 17:56:20 +0200 | [diff] [blame] | 1812 | 		break; | 
| Avi Kivity | 07c45a3 | 2007-03-07 13:05:38 +0200 | [diff] [blame] | 1813 | 	case KVM_GET_VCPU_MMAP_SIZE: | 
 | 1814 | 		r = -EINVAL; | 
 | 1815 | 		if (arg) | 
 | 1816 | 			goto out; | 
| Avi Kivity | adb1ff4 | 2008-01-24 15:13:08 +0200 | [diff] [blame] | 1817 | 		r = PAGE_SIZE;     /* struct kvm_run */ | 
 | 1818 | #ifdef CONFIG_X86 | 
 | 1819 | 		r += PAGE_SIZE;    /* pio data page */ | 
 | 1820 | #endif | 
| Laurent Vivier | 5f94c17 | 2008-05-30 16:05:54 +0200 | [diff] [blame] | 1821 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | 
 | 1822 | 		r += PAGE_SIZE;    /* coalesced mmio ring page */ | 
 | 1823 | #endif | 
| Avi Kivity | 07c45a3 | 2007-03-07 13:05:38 +0200 | [diff] [blame] | 1824 | 		break; | 
| Feng(Eric) Liu | d4c9ff2 | 2008-04-10 08:47:53 -0400 | [diff] [blame] | 1825 | 	case KVM_TRACE_ENABLE: | 
 | 1826 | 	case KVM_TRACE_PAUSE: | 
 | 1827 | 	case KVM_TRACE_DISABLE: | 
| Marcelo Tosatti | 2023a29 | 2009-06-18 11:47:28 -0300 | [diff] [blame] | 1828 | 		r = -EOPNOTSUPP; | 
| Feng(Eric) Liu | d4c9ff2 | 2008-04-10 08:47:53 -0400 | [diff] [blame] | 1829 | 		break; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1830 | 	default: | 
| Carsten Otte | 043405e | 2007-10-10 17:16:19 +0200 | [diff] [blame] | 1831 | 		return kvm_arch_dev_ioctl(filp, ioctl, arg); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1832 | 	} | 
 | 1833 | out: | 
 | 1834 | 	return r; | 
 | 1835 | } | 
 | 1836 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1837 | static struct file_operations kvm_chardev_ops = { | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1838 | 	.unlocked_ioctl = kvm_dev_ioctl, | 
 | 1839 | 	.compat_ioctl   = kvm_dev_ioctl, | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1840 | }; | 
 | 1841 |  | 
 | 1842 | static struct miscdevice kvm_dev = { | 
| Avi Kivity | bbe4432 | 2007-03-04 13:27:36 +0200 | [diff] [blame] | 1843 | 	KVM_MINOR, | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 1844 | 	"kvm", | 
 | 1845 | 	&kvm_chardev_ops, | 
 | 1846 | }; | 
 | 1847 |  | 
| Avi Kivity | 1b6c016 | 2007-05-24 13:03:52 +0300 | [diff] [blame] | 1848 | static void hardware_enable(void *junk) | 
 | 1849 | { | 
 | 1850 | 	int cpu = raw_smp_processor_id(); | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 1851 | 	int r; | 
| Avi Kivity | 1b6c016 | 2007-05-24 13:03:52 +0300 | [diff] [blame] | 1852 |  | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 1853 | 	if (cpumask_test_cpu(cpu, cpus_hardware_enabled)) | 
| Avi Kivity | 1b6c016 | 2007-05-24 13:03:52 +0300 | [diff] [blame] | 1854 | 		return; | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 1855 |  | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 1856 | 	cpumask_set_cpu(cpu, cpus_hardware_enabled); | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 1857 |  | 
 | 1858 | 	r = kvm_arch_hardware_enable(NULL); | 
 | 1859 |  | 
 | 1860 | 	if (r) { | 
 | 1861 | 		cpumask_clear_cpu(cpu, cpus_hardware_enabled); | 
 | 1862 | 		atomic_inc(&hardware_enable_failed); | 
 | 1863 | 		printk(KERN_INFO "kvm: enabling virtualization on " | 
 | 1864 | 				 "CPU%d failed\n", cpu); | 
 | 1865 | 	} | 
| Avi Kivity | 1b6c016 | 2007-05-24 13:03:52 +0300 | [diff] [blame] | 1866 | } | 
 | 1867 |  | 
 | 1868 | static void hardware_disable(void *junk) | 
 | 1869 | { | 
 | 1870 | 	int cpu = raw_smp_processor_id(); | 
 | 1871 |  | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 1872 | 	if (!cpumask_test_cpu(cpu, cpus_hardware_enabled)) | 
| Avi Kivity | 1b6c016 | 2007-05-24 13:03:52 +0300 | [diff] [blame] | 1873 | 		return; | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 1874 | 	cpumask_clear_cpu(cpu, cpus_hardware_enabled); | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 1875 | 	kvm_arch_hardware_disable(NULL); | 
| Avi Kivity | 1b6c016 | 2007-05-24 13:03:52 +0300 | [diff] [blame] | 1876 | } | 
 | 1877 |  | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 1878 | static void hardware_disable_all_nolock(void) | 
 | 1879 | { | 
 | 1880 | 	BUG_ON(!kvm_usage_count); | 
 | 1881 |  | 
 | 1882 | 	kvm_usage_count--; | 
 | 1883 | 	if (!kvm_usage_count) | 
 | 1884 | 		on_each_cpu(hardware_disable, NULL, 1); | 
 | 1885 | } | 
 | 1886 |  | 
 | 1887 | static void hardware_disable_all(void) | 
 | 1888 | { | 
 | 1889 | 	spin_lock(&kvm_lock); | 
 | 1890 | 	hardware_disable_all_nolock(); | 
 | 1891 | 	spin_unlock(&kvm_lock); | 
 | 1892 | } | 
 | 1893 |  | 
 | 1894 | static int hardware_enable_all(void) | 
 | 1895 | { | 
 | 1896 | 	int r = 0; | 
 | 1897 |  | 
 | 1898 | 	spin_lock(&kvm_lock); | 
 | 1899 |  | 
 | 1900 | 	kvm_usage_count++; | 
 | 1901 | 	if (kvm_usage_count == 1) { | 
 | 1902 | 		atomic_set(&hardware_enable_failed, 0); | 
 | 1903 | 		on_each_cpu(hardware_enable, NULL, 1); | 
 | 1904 |  | 
 | 1905 | 		if (atomic_read(&hardware_enable_failed)) { | 
 | 1906 | 			hardware_disable_all_nolock(); | 
 | 1907 | 			r = -EBUSY; | 
 | 1908 | 		} | 
 | 1909 | 	} | 
 | 1910 |  | 
 | 1911 | 	spin_unlock(&kvm_lock); | 
 | 1912 |  | 
 | 1913 | 	return r; | 
 | 1914 | } | 
 | 1915 |  | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 1916 | static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, | 
 | 1917 | 			   void *v) | 
 | 1918 | { | 
 | 1919 | 	int cpu = (long)v; | 
 | 1920 |  | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 1921 | 	if (!kvm_usage_count) | 
 | 1922 | 		return NOTIFY_OK; | 
 | 1923 |  | 
| Avi Kivity | 1a6f4d7 | 2007-11-11 18:37:32 +0200 | [diff] [blame] | 1924 | 	val &= ~CPU_TASKS_FROZEN; | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 1925 | 	switch (val) { | 
| Avi Kivity | cec9ad2 | 2007-05-24 13:11:41 +0300 | [diff] [blame] | 1926 | 	case CPU_DYING: | 
| Avi Kivity | 6ec8a85 | 2007-08-19 15:57:26 +0300 | [diff] [blame] | 1927 | 		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", | 
 | 1928 | 		       cpu); | 
 | 1929 | 		hardware_disable(NULL); | 
 | 1930 | 		break; | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 1931 | 	case CPU_UP_CANCELED: | 
| Jeremy Katz | 43934a3 | 2007-02-19 14:37:46 +0200 | [diff] [blame] | 1932 | 		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", | 
 | 1933 | 		       cpu); | 
| Jens Axboe | 8691e5a | 2008-06-06 11:18:06 +0200 | [diff] [blame] | 1934 | 		smp_call_function_single(cpu, hardware_disable, NULL, 1); | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 1935 | 		break; | 
| Jeremy Katz | 43934a3 | 2007-02-19 14:37:46 +0200 | [diff] [blame] | 1936 | 	case CPU_ONLINE: | 
 | 1937 | 		printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", | 
 | 1938 | 		       cpu); | 
| Jens Axboe | 8691e5a | 2008-06-06 11:18:06 +0200 | [diff] [blame] | 1939 | 		smp_call_function_single(cpu, hardware_enable, NULL, 1); | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 1940 | 		break; | 
 | 1941 | 	} | 
 | 1942 | 	return NOTIFY_OK; | 
 | 1943 | } | 
 | 1944 |  | 
| Avi Kivity | 4ecac3f | 2008-05-13 13:23:38 +0300 | [diff] [blame] | 1945 |  | 
 | 1946 | asmlinkage void kvm_handle_fault_on_reboot(void) | 
 | 1947 | { | 
 | 1948 | 	if (kvm_rebooting) | 
 | 1949 | 		/* spin while reset goes on */ | 
 | 1950 | 		while (true) | 
 | 1951 | 			; | 
 | 1952 | 	/* Fault while not rebooting.  We want the trace. */ | 
 | 1953 | 	BUG(); | 
 | 1954 | } | 
 | 1955 | EXPORT_SYMBOL_GPL(kvm_handle_fault_on_reboot); | 
 | 1956 |  | 
| Rusty Russell | 9a2b85c | 2007-07-17 23:17:55 +1000 | [diff] [blame] | 1957 | static int kvm_reboot(struct notifier_block *notifier, unsigned long val, | 
| Mike Day | d77c26f | 2007-10-08 09:02:08 -0400 | [diff] [blame] | 1958 | 		      void *v) | 
| Rusty Russell | 9a2b85c | 2007-07-17 23:17:55 +1000 | [diff] [blame] | 1959 | { | 
| Sheng Yang | 8e1c181 | 2009-04-29 11:09:04 +0800 | [diff] [blame] | 1960 | 	/* | 
 | 1961 | 	 * Some (well, at least mine) BIOSes hang on reboot if | 
 | 1962 | 	 * in vmx root mode. | 
 | 1963 | 	 * | 
 | 1964 | 	 * And Intel TXT required VMX off for all cpu when system shutdown. | 
 | 1965 | 	 */ | 
 | 1966 | 	printk(KERN_INFO "kvm: exiting hardware virtualization\n"); | 
 | 1967 | 	kvm_rebooting = true; | 
 | 1968 | 	on_each_cpu(hardware_disable, NULL, 1); | 
| Rusty Russell | 9a2b85c | 2007-07-17 23:17:55 +1000 | [diff] [blame] | 1969 | 	return NOTIFY_OK; | 
 | 1970 | } | 
 | 1971 |  | 
 | 1972 | static struct notifier_block kvm_reboot_notifier = { | 
 | 1973 | 	.notifier_call = kvm_reboot, | 
 | 1974 | 	.priority = 0, | 
 | 1975 | }; | 
 | 1976 |  | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 1977 | static void kvm_io_bus_destroy(struct kvm_io_bus *bus) | 
| Gregory Haskins | 2eeb2e9 | 2007-05-31 14:08:53 -0400 | [diff] [blame] | 1978 | { | 
 | 1979 | 	int i; | 
 | 1980 |  | 
 | 1981 | 	for (i = 0; i < bus->dev_count; i++) { | 
 | 1982 | 		struct kvm_io_device *pos = bus->devs[i]; | 
 | 1983 |  | 
 | 1984 | 		kvm_iodevice_destructor(pos); | 
 | 1985 | 	} | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 1986 | 	kfree(bus); | 
| Gregory Haskins | 2eeb2e9 | 2007-05-31 14:08:53 -0400 | [diff] [blame] | 1987 | } | 
 | 1988 |  | 
| Michael S. Tsirkin | bda9020 | 2009-06-29 22:24:32 +0300 | [diff] [blame] | 1989 | /* kvm_io_bus_write - called under kvm->slots_lock */ | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 1990 | int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | 
| Michael S. Tsirkin | bda9020 | 2009-06-29 22:24:32 +0300 | [diff] [blame] | 1991 | 		     int len, const void *val) | 
| Gregory Haskins | 2eeb2e9 | 2007-05-31 14:08:53 -0400 | [diff] [blame] | 1992 | { | 
 | 1993 | 	int i; | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 1994 | 	struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]); | 
| Michael S. Tsirkin | bda9020 | 2009-06-29 22:24:32 +0300 | [diff] [blame] | 1995 | 	for (i = 0; i < bus->dev_count; i++) | 
 | 1996 | 		if (!kvm_iodevice_write(bus->devs[i], addr, len, val)) | 
 | 1997 | 			return 0; | 
 | 1998 | 	return -EOPNOTSUPP; | 
 | 1999 | } | 
| Gregory Haskins | 2eeb2e9 | 2007-05-31 14:08:53 -0400 | [diff] [blame] | 2000 |  | 
| Michael S. Tsirkin | bda9020 | 2009-06-29 22:24:32 +0300 | [diff] [blame] | 2001 | /* kvm_io_bus_read - called under kvm->slots_lock */ | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2002 | int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | 
 | 2003 | 		    int len, void *val) | 
| Michael S. Tsirkin | bda9020 | 2009-06-29 22:24:32 +0300 | [diff] [blame] | 2004 | { | 
 | 2005 | 	int i; | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2006 | 	struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]); | 
 | 2007 |  | 
| Michael S. Tsirkin | bda9020 | 2009-06-29 22:24:32 +0300 | [diff] [blame] | 2008 | 	for (i = 0; i < bus->dev_count; i++) | 
 | 2009 | 		if (!kvm_iodevice_read(bus->devs[i], addr, len, val)) | 
 | 2010 | 			return 0; | 
 | 2011 | 	return -EOPNOTSUPP; | 
| Gregory Haskins | 2eeb2e9 | 2007-05-31 14:08:53 -0400 | [diff] [blame] | 2012 | } | 
 | 2013 |  | 
| Marcelo Tosatti | 79fac95 | 2009-12-23 14:35:26 -0200 | [diff] [blame] | 2014 | /* Caller must hold slots_lock. */ | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2015 | int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, | 
 | 2016 | 			    struct kvm_io_device *dev) | 
| Michael S. Tsirkin | 6c47469 | 2009-06-29 22:24:26 +0300 | [diff] [blame] | 2017 | { | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2018 | 	struct kvm_io_bus *new_bus, *bus; | 
| Gregory Haskins | 090b7af | 2009-07-07 17:08:44 -0400 | [diff] [blame] | 2019 |  | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2020 | 	bus = kvm->buses[bus_idx]; | 
| Gregory Haskins | 090b7af | 2009-07-07 17:08:44 -0400 | [diff] [blame] | 2021 | 	if (bus->dev_count > NR_IOBUS_DEVS-1) | 
 | 2022 | 		return -ENOSPC; | 
 | 2023 |  | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2024 | 	new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL); | 
 | 2025 | 	if (!new_bus) | 
 | 2026 | 		return -ENOMEM; | 
 | 2027 | 	memcpy(new_bus, bus, sizeof(struct kvm_io_bus)); | 
 | 2028 | 	new_bus->devs[new_bus->dev_count++] = dev; | 
 | 2029 | 	rcu_assign_pointer(kvm->buses[bus_idx], new_bus); | 
 | 2030 | 	synchronize_srcu_expedited(&kvm->srcu); | 
 | 2031 | 	kfree(bus); | 
| Gregory Haskins | 090b7af | 2009-07-07 17:08:44 -0400 | [diff] [blame] | 2032 |  | 
 | 2033 | 	return 0; | 
 | 2034 | } | 
 | 2035 |  | 
| Marcelo Tosatti | 79fac95 | 2009-12-23 14:35:26 -0200 | [diff] [blame] | 2036 | /* Caller must hold slots_lock. */ | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2037 | int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, | 
 | 2038 | 			      struct kvm_io_device *dev) | 
| Gregory Haskins | 090b7af | 2009-07-07 17:08:44 -0400 | [diff] [blame] | 2039 | { | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2040 | 	int i, r; | 
 | 2041 | 	struct kvm_io_bus *new_bus, *bus; | 
| Michael S. Tsirkin | 6c47469 | 2009-06-29 22:24:26 +0300 | [diff] [blame] | 2042 |  | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2043 | 	new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL); | 
 | 2044 | 	if (!new_bus) | 
 | 2045 | 		return -ENOMEM; | 
| Gregory Haskins | 2eeb2e9 | 2007-05-31 14:08:53 -0400 | [diff] [blame] | 2046 |  | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2047 | 	bus = kvm->buses[bus_idx]; | 
 | 2048 | 	memcpy(new_bus, bus, sizeof(struct kvm_io_bus)); | 
 | 2049 |  | 
 | 2050 | 	r = -ENOENT; | 
 | 2051 | 	for (i = 0; i < new_bus->dev_count; i++) | 
 | 2052 | 		if (new_bus->devs[i] == dev) { | 
 | 2053 | 			r = 0; | 
 | 2054 | 			new_bus->devs[i] = new_bus->devs[--new_bus->dev_count]; | 
| Gregory Haskins | 090b7af | 2009-07-07 17:08:44 -0400 | [diff] [blame] | 2055 | 			break; | 
 | 2056 | 		} | 
| Marcelo Tosatti | e93f8a0 | 2009-12-23 14:35:24 -0200 | [diff] [blame] | 2057 |  | 
 | 2058 | 	if (r) { | 
 | 2059 | 		kfree(new_bus); | 
 | 2060 | 		return r; | 
 | 2061 | 	} | 
 | 2062 |  | 
 | 2063 | 	rcu_assign_pointer(kvm->buses[bus_idx], new_bus); | 
 | 2064 | 	synchronize_srcu_expedited(&kvm->srcu); | 
 | 2065 | 	kfree(bus); | 
 | 2066 | 	return r; | 
| Gregory Haskins | 2eeb2e9 | 2007-05-31 14:08:53 -0400 | [diff] [blame] | 2067 | } | 
 | 2068 |  | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 2069 | static struct notifier_block kvm_cpu_notifier = { | 
 | 2070 | 	.notifier_call = kvm_cpu_hotplug, | 
 | 2071 | 	.priority = 20, /* must be > scheduler priority */ | 
 | 2072 | }; | 
 | 2073 |  | 
| Christoph Hellwig | 8b88b09 | 2008-02-08 04:20:26 -0800 | [diff] [blame] | 2074 | static int vm_stat_get(void *_offset, u64 *val) | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2075 | { | 
 | 2076 | 	unsigned offset = (long)_offset; | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2077 | 	struct kvm *kvm; | 
 | 2078 |  | 
| Christoph Hellwig | 8b88b09 | 2008-02-08 04:20:26 -0800 | [diff] [blame] | 2079 | 	*val = 0; | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2080 | 	spin_lock(&kvm_lock); | 
 | 2081 | 	list_for_each_entry(kvm, &vm_list, vm_list) | 
| Christoph Hellwig | 8b88b09 | 2008-02-08 04:20:26 -0800 | [diff] [blame] | 2082 | 		*val += *(u32 *)((void *)kvm + offset); | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2083 | 	spin_unlock(&kvm_lock); | 
| Christoph Hellwig | 8b88b09 | 2008-02-08 04:20:26 -0800 | [diff] [blame] | 2084 | 	return 0; | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2085 | } | 
 | 2086 |  | 
 | 2087 | DEFINE_SIMPLE_ATTRIBUTE(vm_stat_fops, vm_stat_get, NULL, "%llu\n"); | 
 | 2088 |  | 
| Christoph Hellwig | 8b88b09 | 2008-02-08 04:20:26 -0800 | [diff] [blame] | 2089 | static int vcpu_stat_get(void *_offset, u64 *val) | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 2090 | { | 
 | 2091 | 	unsigned offset = (long)_offset; | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 2092 | 	struct kvm *kvm; | 
 | 2093 | 	struct kvm_vcpu *vcpu; | 
 | 2094 | 	int i; | 
 | 2095 |  | 
| Christoph Hellwig | 8b88b09 | 2008-02-08 04:20:26 -0800 | [diff] [blame] | 2096 | 	*val = 0; | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 2097 | 	spin_lock(&kvm_lock); | 
 | 2098 | 	list_for_each_entry(kvm, &vm_list, vm_list) | 
| Gleb Natapov | 988a2ca | 2009-06-09 15:56:29 +0300 | [diff] [blame] | 2099 | 		kvm_for_each_vcpu(i, vcpu, kvm) | 
 | 2100 | 			*val += *(u32 *)((void *)vcpu + offset); | 
 | 2101 |  | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 2102 | 	spin_unlock(&kvm_lock); | 
| Christoph Hellwig | 8b88b09 | 2008-02-08 04:20:26 -0800 | [diff] [blame] | 2103 | 	return 0; | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 2104 | } | 
 | 2105 |  | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2106 | DEFINE_SIMPLE_ATTRIBUTE(vcpu_stat_fops, vcpu_stat_get, NULL, "%llu\n"); | 
 | 2107 |  | 
| Alexey Dobriyan | 828c095 | 2009-10-01 15:43:56 -0700 | [diff] [blame] | 2108 | static const struct file_operations *stat_fops[] = { | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2109 | 	[KVM_STAT_VCPU] = &vcpu_stat_fops, | 
 | 2110 | 	[KVM_STAT_VM]   = &vm_stat_fops, | 
 | 2111 | }; | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 2112 |  | 
| Zhang Xiantao | a16b043 | 2007-11-16 14:38:21 +0800 | [diff] [blame] | 2113 | static void kvm_init_debug(void) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2114 | { | 
 | 2115 | 	struct kvm_stats_debugfs_item *p; | 
 | 2116 |  | 
| Hollis Blanchard | 76f7c87 | 2008-04-15 16:05:42 -0500 | [diff] [blame] | 2117 | 	kvm_debugfs_dir = debugfs_create_dir("kvm", NULL); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2118 | 	for (p = debugfs_entries; p->name; ++p) | 
| Hollis Blanchard | 76f7c87 | 2008-04-15 16:05:42 -0500 | [diff] [blame] | 2119 | 		p->dentry = debugfs_create_file(p->name, 0444, kvm_debugfs_dir, | 
| Avi Kivity | 1165f5f | 2007-04-19 17:27:43 +0300 | [diff] [blame] | 2120 | 						(void *)(long)p->offset, | 
| Avi Kivity | ba1389b | 2007-11-18 16:24:12 +0200 | [diff] [blame] | 2121 | 						stat_fops[p->kind]); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2122 | } | 
 | 2123 |  | 
 | 2124 | static void kvm_exit_debug(void) | 
 | 2125 | { | 
 | 2126 | 	struct kvm_stats_debugfs_item *p; | 
 | 2127 |  | 
 | 2128 | 	for (p = debugfs_entries; p->name; ++p) | 
 | 2129 | 		debugfs_remove(p->dentry); | 
| Hollis Blanchard | 76f7c87 | 2008-04-15 16:05:42 -0500 | [diff] [blame] | 2130 | 	debugfs_remove(kvm_debugfs_dir); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2131 | } | 
 | 2132 |  | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2133 | static int kvm_suspend(struct sys_device *dev, pm_message_t state) | 
 | 2134 | { | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 2135 | 	if (kvm_usage_count) | 
 | 2136 | 		hardware_disable(NULL); | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2137 | 	return 0; | 
 | 2138 | } | 
 | 2139 |  | 
 | 2140 | static int kvm_resume(struct sys_device *dev) | 
 | 2141 | { | 
| Alexander Graf | 10474ae | 2009-09-15 11:37:46 +0200 | [diff] [blame] | 2142 | 	if (kvm_usage_count) | 
 | 2143 | 		hardware_enable(NULL); | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2144 | 	return 0; | 
 | 2145 | } | 
 | 2146 |  | 
 | 2147 | static struct sysdev_class kvm_sysdev_class = { | 
| Kay Sievers | af5ca3f | 2007-12-20 02:09:39 +0100 | [diff] [blame] | 2148 | 	.name = "kvm", | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2149 | 	.suspend = kvm_suspend, | 
 | 2150 | 	.resume = kvm_resume, | 
 | 2151 | }; | 
 | 2152 |  | 
 | 2153 | static struct sys_device kvm_sysdev = { | 
 | 2154 | 	.id = 0, | 
 | 2155 | 	.cls = &kvm_sysdev_class, | 
 | 2156 | }; | 
 | 2157 |  | 
| Izik Eidus | cea7bb2 | 2007-10-17 19:17:48 +0200 | [diff] [blame] | 2158 | struct page *bad_page; | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 2159 | pfn_t bad_pfn; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2160 |  | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 2161 | static inline | 
 | 2162 | struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) | 
 | 2163 | { | 
 | 2164 | 	return container_of(pn, struct kvm_vcpu, preempt_notifier); | 
 | 2165 | } | 
 | 2166 |  | 
 | 2167 | static void kvm_sched_in(struct preempt_notifier *pn, int cpu) | 
 | 2168 | { | 
 | 2169 | 	struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); | 
 | 2170 |  | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 2171 | 	kvm_arch_vcpu_load(vcpu, cpu); | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 2172 | } | 
 | 2173 |  | 
 | 2174 | static void kvm_sched_out(struct preempt_notifier *pn, | 
 | 2175 | 			  struct task_struct *next) | 
 | 2176 | { | 
 | 2177 | 	struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); | 
 | 2178 |  | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 2179 | 	kvm_arch_vcpu_put(vcpu); | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 2180 | } | 
 | 2181 |  | 
| Zhang Xiantao | f8c16bb | 2007-11-14 20:40:21 +0800 | [diff] [blame] | 2182 | int kvm_init(void *opaque, unsigned int vcpu_size, | 
| Rusty Russell | c16f862 | 2007-07-30 21:12:19 +1000 | [diff] [blame] | 2183 | 		  struct module *module) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2184 | { | 
 | 2185 | 	int r; | 
| Yang, Sheng | 002c7f7 | 2007-07-31 14:23:01 +0300 | [diff] [blame] | 2186 | 	int cpu; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2187 |  | 
| Zhang Xiantao | f8c16bb | 2007-11-14 20:40:21 +0800 | [diff] [blame] | 2188 | 	r = kvm_arch_init(opaque); | 
 | 2189 | 	if (r) | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2190 | 		goto out_fail; | 
| Zhang Xiantao | cb498ea | 2007-11-14 20:39:31 +0800 | [diff] [blame] | 2191 |  | 
 | 2192 | 	bad_page = alloc_page(GFP_KERNEL | __GFP_ZERO); | 
 | 2193 |  | 
 | 2194 | 	if (bad_page == NULL) { | 
 | 2195 | 		r = -ENOMEM; | 
 | 2196 | 		goto out; | 
 | 2197 | 	} | 
 | 2198 |  | 
| Anthony Liguori | 35149e2 | 2008-04-02 14:46:56 -0500 | [diff] [blame] | 2199 | 	bad_pfn = page_to_pfn(bad_page); | 
 | 2200 |  | 
| Avi Kivity | 8437a61 | 2009-06-06 14:52:35 -0700 | [diff] [blame] | 2201 | 	if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 2202 | 		r = -ENOMEM; | 
 | 2203 | 		goto out_free_0; | 
 | 2204 | 	} | 
 | 2205 |  | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 2206 | 	r = kvm_arch_hardware_setup(); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2207 | 	if (r < 0) | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 2208 | 		goto out_free_0a; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2209 |  | 
| Yang, Sheng | 002c7f7 | 2007-07-31 14:23:01 +0300 | [diff] [blame] | 2210 | 	for_each_online_cpu(cpu) { | 
 | 2211 | 		smp_call_function_single(cpu, | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 2212 | 				kvm_arch_check_processor_compat, | 
| Jens Axboe | 8691e5a | 2008-06-06 11:18:06 +0200 | [diff] [blame] | 2213 | 				&r, 1); | 
| Yang, Sheng | 002c7f7 | 2007-07-31 14:23:01 +0300 | [diff] [blame] | 2214 | 		if (r < 0) | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2215 | 			goto out_free_1; | 
| Yang, Sheng | 002c7f7 | 2007-07-31 14:23:01 +0300 | [diff] [blame] | 2216 | 	} | 
 | 2217 |  | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 2218 | 	r = register_cpu_notifier(&kvm_cpu_notifier); | 
 | 2219 | 	if (r) | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2220 | 		goto out_free_2; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2221 | 	register_reboot_notifier(&kvm_reboot_notifier); | 
 | 2222 |  | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2223 | 	r = sysdev_class_register(&kvm_sysdev_class); | 
 | 2224 | 	if (r) | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2225 | 		goto out_free_3; | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2226 |  | 
 | 2227 | 	r = sysdev_register(&kvm_sysdev); | 
 | 2228 | 	if (r) | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2229 | 		goto out_free_4; | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2230 |  | 
| Rusty Russell | c16f862 | 2007-07-30 21:12:19 +1000 | [diff] [blame] | 2231 | 	/* A kmem cache lets us meet the alignment requirements of fx_save. */ | 
 | 2232 | 	kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, | 
| Joe Perches | 56919c5 | 2007-11-12 20:06:51 -0800 | [diff] [blame] | 2233 | 					   __alignof__(struct kvm_vcpu), | 
 | 2234 | 					   0, NULL); | 
| Rusty Russell | c16f862 | 2007-07-30 21:12:19 +1000 | [diff] [blame] | 2235 | 	if (!kvm_vcpu_cache) { | 
 | 2236 | 		r = -ENOMEM; | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2237 | 		goto out_free_5; | 
| Rusty Russell | c16f862 | 2007-07-30 21:12:19 +1000 | [diff] [blame] | 2238 | 	} | 
 | 2239 |  | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2240 | 	kvm_chardev_ops.owner = module; | 
| Christian Borntraeger | 3d3aab1 | 2008-12-02 11:17:32 +0100 | [diff] [blame] | 2241 | 	kvm_vm_fops.owner = module; | 
 | 2242 | 	kvm_vcpu_fops.owner = module; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2243 |  | 
 | 2244 | 	r = misc_register(&kvm_dev); | 
 | 2245 | 	if (r) { | 
| Mike Day | d77c26f | 2007-10-08 09:02:08 -0400 | [diff] [blame] | 2246 | 		printk(KERN_ERR "kvm: misc device register failed\n"); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2247 | 		goto out_free; | 
 | 2248 | 	} | 
 | 2249 |  | 
| Avi Kivity | 15ad714 | 2007-07-11 18:17:21 +0300 | [diff] [blame] | 2250 | 	kvm_preempt_ops.sched_in = kvm_sched_in; | 
 | 2251 | 	kvm_preempt_ops.sched_out = kvm_sched_out; | 
 | 2252 |  | 
| Darrick J. Wong | 0ea4ed8 | 2009-10-14 16:21:00 -0700 | [diff] [blame] | 2253 | 	kvm_init_debug(); | 
 | 2254 |  | 
| Avi Kivity | c7addb9 | 2007-09-16 18:58:32 +0200 | [diff] [blame] | 2255 | 	return 0; | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2256 |  | 
 | 2257 | out_free: | 
| Rusty Russell | c16f862 | 2007-07-30 21:12:19 +1000 | [diff] [blame] | 2258 | 	kmem_cache_destroy(kvm_vcpu_cache); | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2259 | out_free_5: | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2260 | 	sysdev_unregister(&kvm_sysdev); | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2261 | out_free_4: | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2262 | 	sysdev_class_unregister(&kvm_sysdev_class); | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2263 | out_free_3: | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2264 | 	unregister_reboot_notifier(&kvm_reboot_notifier); | 
| Avi Kivity | 774c47f | 2007-02-12 00:54:47 -0800 | [diff] [blame] | 2265 | 	unregister_cpu_notifier(&kvm_cpu_notifier); | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2266 | out_free_2: | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2267 | out_free_1: | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 2268 | 	kvm_arch_hardware_unsetup(); | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 2269 | out_free_0a: | 
 | 2270 | 	free_cpumask_var(cpus_hardware_enabled); | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2271 | out_free_0: | 
 | 2272 | 	__free_page(bad_page); | 
| Avi Kivity | ca45aaa | 2007-03-01 19:21:03 +0200 | [diff] [blame] | 2273 | out: | 
| Zhang Xiantao | f8c16bb | 2007-11-14 20:40:21 +0800 | [diff] [blame] | 2274 | 	kvm_arch_exit(); | 
| Zhang Xiantao | d2308784 | 2007-11-29 15:35:39 +0800 | [diff] [blame] | 2275 | out_fail: | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2276 | 	return r; | 
 | 2277 | } | 
| Zhang Xiantao | cb498ea | 2007-11-14 20:39:31 +0800 | [diff] [blame] | 2278 | EXPORT_SYMBOL_GPL(kvm_init); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2279 |  | 
| Zhang Xiantao | cb498ea | 2007-11-14 20:39:31 +0800 | [diff] [blame] | 2280 | void kvm_exit(void) | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2281 | { | 
| Marcelo Tosatti | 229456f | 2009-06-17 09:22:14 -0300 | [diff] [blame] | 2282 | 	tracepoint_synchronize_unregister(); | 
| Darrick J. Wong | 0ea4ed8 | 2009-10-14 16:21:00 -0700 | [diff] [blame] | 2283 | 	kvm_exit_debug(); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2284 | 	misc_deregister(&kvm_dev); | 
| Rusty Russell | c16f862 | 2007-07-30 21:12:19 +1000 | [diff] [blame] | 2285 | 	kmem_cache_destroy(kvm_vcpu_cache); | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2286 | 	sysdev_unregister(&kvm_sysdev); | 
 | 2287 | 	sysdev_class_unregister(&kvm_sysdev_class); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2288 | 	unregister_reboot_notifier(&kvm_reboot_notifier); | 
| Avi Kivity | 59ae6c6 | 2007-02-12 00:54:48 -0800 | [diff] [blame] | 2289 | 	unregister_cpu_notifier(&kvm_cpu_notifier); | 
| Jens Axboe | 15c8b6c | 2008-05-09 09:39:44 +0200 | [diff] [blame] | 2290 | 	on_each_cpu(hardware_disable, NULL, 1); | 
| Zhang Xiantao | e9b11c1 | 2007-11-14 20:38:21 +0800 | [diff] [blame] | 2291 | 	kvm_arch_hardware_unsetup(); | 
| Zhang Xiantao | f8c16bb | 2007-11-14 20:40:21 +0800 | [diff] [blame] | 2292 | 	kvm_arch_exit(); | 
| Rusty Russell | 7f59f49 | 2008-12-07 21:25:45 +1030 | [diff] [blame] | 2293 | 	free_cpumask_var(cpus_hardware_enabled); | 
| Izik Eidus | cea7bb2 | 2007-10-17 19:17:48 +0200 | [diff] [blame] | 2294 | 	__free_page(bad_page); | 
| Avi Kivity | 6aa8b73 | 2006-12-10 02:21:36 -0800 | [diff] [blame] | 2295 | } | 
| Zhang Xiantao | cb498ea | 2007-11-14 20:39:31 +0800 | [diff] [blame] | 2296 | EXPORT_SYMBOL_GPL(kvm_exit); |