diff options
author | Carsten Otte <cotte@de.ibm.com> | 2007-10-30 13:44:25 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:59 -0500 |
commit | de7d789acd7f373268194bb48dc0690c975ab8e6 (patch) | |
tree | c2e9c4e1bb8d127e7a53459f9ed83c711901f31d /drivers/kvm/kvm_main.c | |
parent | bbd9b64e37aff5aa715ec5e168425790f5983bf1 (diff) |
KVM: Portability: Move pio emulation functions to x86.c
This patch moves implementation of the following functions from
kvm_main.c to x86.c:
free_pio_guest_pages, vcpu_find_pio_dev, pio_copy_data, complete_pio,
kernel_pio, pio_string_write, kvm_emulate_pio, kvm_emulate_pio_string
The function inject_gp, which was duplicated by yesterday's patch
series, is removed from kvm_main.c now because it is not needed anymore.
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Acked-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 248 |
1 files changed, 0 insertions, 248 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 1a56d76560de..2025cdfb4593 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -271,17 +271,6 @@ static void kvm_free_physmem(struct kvm *kvm) | |||
271 | kvm_free_physmem_slot(&kvm->memslots[i], NULL); | 271 | kvm_free_physmem_slot(&kvm->memslots[i], NULL); |
272 | } | 272 | } |
273 | 273 | ||
274 | static void free_pio_guest_pages(struct kvm_vcpu *vcpu) | ||
275 | { | ||
276 | int i; | ||
277 | |||
278 | for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i) | ||
279 | if (vcpu->pio.guest_pages[i]) { | ||
280 | kvm_release_page(vcpu->pio.guest_pages[i]); | ||
281 | vcpu->pio.guest_pages[i] = NULL; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) | 274 | static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) |
286 | { | 275 | { |
287 | vcpu_load(vcpu); | 276 | vcpu_load(vcpu); |
@@ -330,11 +319,6 @@ static int kvm_vm_release(struct inode *inode, struct file *filp) | |||
330 | return 0; | 319 | return 0; |
331 | } | 320 | } |
332 | 321 | ||
333 | static void inject_gp(struct kvm_vcpu *vcpu) | ||
334 | { | ||
335 | kvm_x86_ops->inject_gp(vcpu, 0); | ||
336 | } | ||
337 | |||
338 | void fx_init(struct kvm_vcpu *vcpu) | 322 | void fx_init(struct kvm_vcpu *vcpu) |
339 | { | 323 | { |
340 | unsigned after_mxcsr_mask; | 324 | unsigned after_mxcsr_mask; |
@@ -827,12 +811,6 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) | |||
827 | } | 811 | } |
828 | } | 812 | } |
829 | 813 | ||
830 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, | ||
831 | gpa_t addr) | ||
832 | { | ||
833 | return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr); | ||
834 | } | ||
835 | |||
836 | /* | 814 | /* |
837 | * The vCPU has executed a HLT instruction with in-kernel mode enabled. | 815 | * The vCPU has executed a HLT instruction with in-kernel mode enabled. |
838 | */ | 816 | */ |
@@ -1042,232 +1020,6 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) | |||
1042 | } | 1020 | } |
1043 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); | 1021 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); |
1044 | 1022 | ||
1045 | static int pio_copy_data(struct kvm_vcpu *vcpu) | ||
1046 | { | ||
1047 | void *p = vcpu->pio_data; | ||
1048 | void *q; | ||
1049 | unsigned bytes; | ||
1050 | int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; | ||
1051 | |||
1052 | q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, | ||
1053 | PAGE_KERNEL); | ||
1054 | if (!q) { | ||
1055 | free_pio_guest_pages(vcpu); | ||
1056 | return -ENOMEM; | ||
1057 | } | ||
1058 | q += vcpu->pio.guest_page_offset; | ||
1059 | bytes = vcpu->pio.size * vcpu->pio.cur_count; | ||
1060 | if (vcpu->pio.in) | ||
1061 | memcpy(q, p, bytes); | ||
1062 | else | ||
1063 | memcpy(p, q, bytes); | ||
1064 | q -= vcpu->pio.guest_page_offset; | ||
1065 | vunmap(q); | ||
1066 | free_pio_guest_pages(vcpu); | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static int complete_pio(struct kvm_vcpu *vcpu) | ||
1071 | { | ||
1072 | struct kvm_pio_request *io = &vcpu->pio; | ||
1073 | long delta; | ||
1074 | int r; | ||
1075 | |||
1076 | kvm_x86_ops->cache_regs(vcpu); | ||
1077 | |||
1078 | if (!io->string) { | ||
1079 | if (io->in) | ||
1080 | memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data, | ||
1081 | io->size); | ||
1082 | } else { | ||
1083 | if (io->in) { | ||
1084 | r = pio_copy_data(vcpu); | ||
1085 | if (r) { | ||
1086 | kvm_x86_ops->cache_regs(vcpu); | ||
1087 | return r; | ||
1088 | } | ||
1089 | } | ||
1090 | |||
1091 | delta = 1; | ||
1092 | if (io->rep) { | ||
1093 | delta *= io->cur_count; | ||
1094 | /* | ||
1095 | * The size of the register should really depend on | ||
1096 | * current address size. | ||
1097 | */ | ||
1098 | vcpu->regs[VCPU_REGS_RCX] -= delta; | ||
1099 | } | ||
1100 | if (io->down) | ||
1101 | delta = -delta; | ||
1102 | delta *= io->size; | ||
1103 | if (io->in) | ||
1104 | vcpu->regs[VCPU_REGS_RDI] += delta; | ||
1105 | else | ||
1106 | vcpu->regs[VCPU_REGS_RSI] += delta; | ||
1107 | } | ||
1108 | |||
1109 | kvm_x86_ops->decache_regs(vcpu); | ||
1110 | |||
1111 | io->count -= io->cur_count; | ||
1112 | io->cur_count = 0; | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | static void kernel_pio(struct kvm_io_device *pio_dev, | ||
1118 | struct kvm_vcpu *vcpu, | ||
1119 | void *pd) | ||
1120 | { | ||
1121 | /* TODO: String I/O for in kernel device */ | ||
1122 | |||
1123 | mutex_lock(&vcpu->kvm->lock); | ||
1124 | if (vcpu->pio.in) | ||
1125 | kvm_iodevice_read(pio_dev, vcpu->pio.port, | ||
1126 | vcpu->pio.size, | ||
1127 | pd); | ||
1128 | else | ||
1129 | kvm_iodevice_write(pio_dev, vcpu->pio.port, | ||
1130 | vcpu->pio.size, | ||
1131 | pd); | ||
1132 | mutex_unlock(&vcpu->kvm->lock); | ||
1133 | } | ||
1134 | |||
1135 | static void pio_string_write(struct kvm_io_device *pio_dev, | ||
1136 | struct kvm_vcpu *vcpu) | ||
1137 | { | ||
1138 | struct kvm_pio_request *io = &vcpu->pio; | ||
1139 | void *pd = vcpu->pio_data; | ||
1140 | int i; | ||
1141 | |||
1142 | mutex_lock(&vcpu->kvm->lock); | ||
1143 | for (i = 0; i < io->cur_count; i++) { | ||
1144 | kvm_iodevice_write(pio_dev, io->port, | ||
1145 | io->size, | ||
1146 | pd); | ||
1147 | pd += io->size; | ||
1148 | } | ||
1149 | mutex_unlock(&vcpu->kvm->lock); | ||
1150 | } | ||
1151 | |||
1152 | int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | ||
1153 | int size, unsigned port) | ||
1154 | { | ||
1155 | struct kvm_io_device *pio_dev; | ||
1156 | |||
1157 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
1158 | vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; | ||
1159 | vcpu->run->io.size = vcpu->pio.size = size; | ||
1160 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
1161 | vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1; | ||
1162 | vcpu->run->io.port = vcpu->pio.port = port; | ||
1163 | vcpu->pio.in = in; | ||
1164 | vcpu->pio.string = 0; | ||
1165 | vcpu->pio.down = 0; | ||
1166 | vcpu->pio.guest_page_offset = 0; | ||
1167 | vcpu->pio.rep = 0; | ||
1168 | |||
1169 | kvm_x86_ops->cache_regs(vcpu); | ||
1170 | memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); | ||
1171 | kvm_x86_ops->decache_regs(vcpu); | ||
1172 | |||
1173 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1174 | |||
1175 | pio_dev = vcpu_find_pio_dev(vcpu, port); | ||
1176 | if (pio_dev) { | ||
1177 | kernel_pio(pio_dev, vcpu, vcpu->pio_data); | ||
1178 | complete_pio(vcpu); | ||
1179 | return 1; | ||
1180 | } | ||
1181 | return 0; | ||
1182 | } | ||
1183 | EXPORT_SYMBOL_GPL(kvm_emulate_pio); | ||
1184 | |||
1185 | int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | ||
1186 | int size, unsigned long count, int down, | ||
1187 | gva_t address, int rep, unsigned port) | ||
1188 | { | ||
1189 | unsigned now, in_page; | ||
1190 | int i, ret = 0; | ||
1191 | int nr_pages = 1; | ||
1192 | struct page *page; | ||
1193 | struct kvm_io_device *pio_dev; | ||
1194 | |||
1195 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
1196 | vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; | ||
1197 | vcpu->run->io.size = vcpu->pio.size = size; | ||
1198 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
1199 | vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count; | ||
1200 | vcpu->run->io.port = vcpu->pio.port = port; | ||
1201 | vcpu->pio.in = in; | ||
1202 | vcpu->pio.string = 1; | ||
1203 | vcpu->pio.down = down; | ||
1204 | vcpu->pio.guest_page_offset = offset_in_page(address); | ||
1205 | vcpu->pio.rep = rep; | ||
1206 | |||
1207 | if (!count) { | ||
1208 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1209 | return 1; | ||
1210 | } | ||
1211 | |||
1212 | if (!down) | ||
1213 | in_page = PAGE_SIZE - offset_in_page(address); | ||
1214 | else | ||
1215 | in_page = offset_in_page(address) + size; | ||
1216 | now = min(count, (unsigned long)in_page / size); | ||
1217 | if (!now) { | ||
1218 | /* | ||
1219 | * String I/O straddles page boundary. Pin two guest pages | ||
1220 | * so that we satisfy atomicity constraints. Do just one | ||
1221 | * transaction to avoid complexity. | ||
1222 | */ | ||
1223 | nr_pages = 2; | ||
1224 | now = 1; | ||
1225 | } | ||
1226 | if (down) { | ||
1227 | /* | ||
1228 | * String I/O in reverse. Yuck. Kill the guest, fix later. | ||
1229 | */ | ||
1230 | pr_unimpl(vcpu, "guest string pio down\n"); | ||
1231 | inject_gp(vcpu); | ||
1232 | return 1; | ||
1233 | } | ||
1234 | vcpu->run->io.count = now; | ||
1235 | vcpu->pio.cur_count = now; | ||
1236 | |||
1237 | if (vcpu->pio.cur_count == vcpu->pio.count) | ||
1238 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1239 | |||
1240 | for (i = 0; i < nr_pages; ++i) { | ||
1241 | mutex_lock(&vcpu->kvm->lock); | ||
1242 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); | ||
1243 | vcpu->pio.guest_pages[i] = page; | ||
1244 | mutex_unlock(&vcpu->kvm->lock); | ||
1245 | if (!page) { | ||
1246 | inject_gp(vcpu); | ||
1247 | free_pio_guest_pages(vcpu); | ||
1248 | return 1; | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | pio_dev = vcpu_find_pio_dev(vcpu, port); | ||
1253 | if (!vcpu->pio.in) { | ||
1254 | /* string PIO write */ | ||
1255 | ret = pio_copy_data(vcpu); | ||
1256 | if (ret >= 0 && pio_dev) { | ||
1257 | pio_string_write(pio_dev, vcpu); | ||
1258 | complete_pio(vcpu); | ||
1259 | if (vcpu->pio.count == 0) | ||
1260 | ret = 1; | ||
1261 | } | ||
1262 | } else if (pio_dev) | ||
1263 | pr_unimpl(vcpu, "no string pio read support yet, " | ||
1264 | "port %x size %d count %ld\n", | ||
1265 | port, size, count); | ||
1266 | |||
1267 | return ret; | ||
1268 | } | ||
1269 | EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); | ||
1270 | |||
1271 | /* | 1023 | /* |
1272 | * Check if userspace requested an interrupt window, and that the | 1024 | * Check if userspace requested an interrupt window, and that the |
1273 | * interrupt window is open. | 1025 | * interrupt window is open. |